View | Details | Raw Unified | Return to bug 40369
Collapse All | Expand All

(-)bin/jmeter.properties (+16 lines)
Lines 407-412 Link Here
407
#beanshell.server.port=9000
407
#beanshell.server.port=9000
408
# The telnet server will be started on the next port
408
# The telnet server will be started on the next port
409
409
410
#---------------------------------------------------------------------------
411
# LDAP Sampler configuration
412
#---------------------------------------------------------------------------
413
# Maximum number of search results returned by a search that will be sorted
414
# to guarantee a stable ordering (if more results then this limit are retruned
415
# then no sorting is done). Set to 0 to turn off all sorting, in which case
416
# "Equals" response assertions will be very likely to fail against search results.
417
#ldapsampler.max_sorted_results=2000
418
ldapsampler.max_sorted_results=2000
419
410
#
420
#
411
# Define the server initialisation file
421
# Define the server initialisation file
412
beanshell.server.file=../extras/startup.bsh
422
beanshell.server.file=../extras/startup.bsh
Lines 507-512 Link Here
507
#Should JMeter expand the tree when loading a test plan?
517
#Should JMeter expand the tree when loading a test plan?
508
#onload.expandtree=false
518
#onload.expandtree=false
509
519
520
# Number of characters to log for each of three sections (starting matching section, diff section,
521
#   ending matching section where not all sections will appear for all diffs) diff display when an Equals
522
#   assertion fails. So a value of 50 means a maximum of 150 characters of diff text will be displayed
523
#   (+ a number of extra characters like "..." and "<<"/">>" which are used to decorate it).
524
#assertion.equals_section_diff_len=50
525
510
# Should JMeter automatically load additional JMeter properties?
526
# Should JMeter automatically load additional JMeter properties?
511
# File name to look for (comment to disable)
527
# File name to look for (comment to disable)
512
user.properties=user.properties
528
user.properties=user.properties
(-)src/components/org/apache/jmeter/assertions/gui/AssertionGui.java (-6 / +23 lines)
Lines 81-86 Link Here
81
	private JRadioButton matchesBox;
81
	private JRadioButton matchesBox;
82
82
83
	/**
83
	/**
84
	 * Radio button indicating if the field equals the first pattern.
85
	 */
86
	private JRadioButton equalsBox;
87
88
    /**
84
	 * Checkbox indicating to test that the field does NOT contain/match the
89
	 * Checkbox indicating to test that the field does NOT contain/match the
85
	 * patterns.
90
	 * patterns.
86
	 */
91
	 */
Lines 142-152 Link Here
142
147
143
			if (containsBox.isSelected()) {
148
			if (containsBox.isSelected()) {
144
				ra.setToContainsType();
149
				ra.setToContainsType();
150
			} else if (matchesBox.isSelected()) {
151
				ra.setToMatchType();
145
			} else {
152
			} else {
146
				ra.setToMatchType();
153
                ra.setToEqualsType();
147
			}
154
            }
148
155
149
			if (notBox.isSelected()) {
156
            if (notBox.isSelected()) {
150
				ra.setToNotType();
157
				ra.setToNotType();
151
			} else {
158
			} else {
152
				ra.unsetNotType();
159
				ra.unsetNotType();
Lines 170-179 Link Here
170
		if (model.isContainsType()) {
177
		if (model.isContainsType()) {
171
			containsBox.setSelected(true);
178
			containsBox.setSelected(true);
172
			matchesBox.setSelected(false);
179
			matchesBox.setSelected(false);
180
            equalsBox.setSelected(false);
181
        } else if (model.isMatchType()) {
182
			containsBox.setSelected(false);
183
			matchesBox.setSelected(true);
184
            equalsBox.setSelected(false);
173
		} else {
185
		} else {
174
			containsBox.setSelected(false);
186
			containsBox.setSelected(false);
175
			matchesBox.setSelected(true);
187
			matchesBox.setSelected(false);
176
		}
188
            equalsBox.setSelected(true);
189
        }
177
190
178
		if (model.isNotType()) {
191
		if (model.isNotType()) {
179
			notBox.setSelected(true);
192
			notBox.setSelected(true);
Lines 279-285 Link Here
279
		group.add(matchesBox);
292
		group.add(matchesBox);
280
		panel.add(matchesBox);
293
		panel.add(matchesBox);
281
294
282
		notBox = new JCheckBox(JMeterUtils.getResString("assertion_not"));
295
		equalsBox = new JRadioButton(JMeterUtils.getResString("assertion_equals"));
296
		group.add(equalsBox);
297
		panel.add(equalsBox);
298
299
        notBox = new JCheckBox(JMeterUtils.getResString("assertion_not"));
283
		panel.add(notBox);
300
		panel.add(notBox);
284
301
285
		return panel;
302
		return panel;
(-)src/components/org/apache/jmeter/assertions/ResponseAssertion.java (-66 / +241 lines)
Lines 28-33 Link Here
28
import org.apache.jmeter.testelement.property.NullProperty;
28
import org.apache.jmeter.testelement.property.NullProperty;
29
import org.apache.jmeter.testelement.property.PropertyIterator;
29
import org.apache.jmeter.testelement.property.PropertyIterator;
30
import org.apache.jmeter.testelement.property.StringProperty;
30
import org.apache.jmeter.testelement.property.StringProperty;
31
import org.apache.jmeter.util.JMeterUtils;
31
import org.apache.jorphan.logging.LoggingManager;
32
import org.apache.jorphan.logging.LoggingManager;
32
import org.apache.jorphan.util.JOrphanUtils;
33
import org.apache.jorphan.util.JOrphanUtils;
33
import org.apache.log.Logger;
34
import org.apache.log.Logger;
Lines 58-64 Link Here
58
59
59
	public final static String ASSUME_SUCCESS = "Assertion.assume_success"; // $NON-NLS-1$
60
	public final static String ASSUME_SUCCESS = "Assertion.assume_success"; // $NON-NLS-1$
60
61
61
	public final static String TEST_STRINGS = "Asserion.test_strings"; // $NON-NLS-1$
62
	public final static String TEST_STRINGS = "Assertion.test_strings"; // $NON-NLS-1$
62
63
63
	public final static String TEST_TYPE = "Assertion.test_type"; // $NON-NLS-1$
64
	public final static String TEST_TYPE = "Assertion.test_type"; // $NON-NLS-1$
64
65
Lines 72-92 Link Here
72
73
73
	private final static int NOT = 1 << 2;
74
	private final static int NOT = 1 << 2;
74
75
75
	private static ThreadLocal matcher = new ThreadLocal() {
76
	private final static int EQUALS = 1 << 3;
77
78
    private static ThreadLocal matcher = new ThreadLocal() {
76
		protected Object initialValue() {
79
		protected Object initialValue() {
77
			return new Perl5Matcher();
80
			return new Perl5Matcher();
78
		}
81
		}
79
	};
82
	};
80
83
81
	private static final PatternCacheLRU patternCache = new PatternCacheLRU(1000, new Perl5Compiler());
84
    protected static final int  EQUALS_SECTION_DIFF_LEN
85
            = JMeterUtils.getPropDefault("assertion.equals_section_diff_len", 50);
82
86
83
	/***************************************************************************
87
    /** Signifies truncated text in diff display. */
84
	 * !ToDo (Constructor description)
88
    private static final String EQUALS_DIFF_TRUNC = "...";
85
	 **************************************************************************/
86
	public ResponseAssertion() {
87
		setProperty(new CollectionProperty(TEST_STRINGS, new ArrayList()));
88
	}
89
89
90
    private static final PatternCacheLRU patternCache = new PatternCacheLRU(1000, new Perl5Compiler());
91
    private static final String COMPARISON_STR = "comparison: ";
92
    private static final String RECEIVED_STR = "received  : ";
93
    private static final String DIFF_DELTA_PRE = "<<";
94
    private static final String DIFF_DELTA_POST = ">>";
95
96
    /***************************************************************************
97
     * !ToDo (Constructor description)
98
     **************************************************************************/
99
    public ResponseAssertion() {
100
        setProperty(new CollectionProperty(TEST_STRINGS, new ArrayList()));
101
    }
102
90
	/***************************************************************************
103
	/***************************************************************************
91
	 * !ToDo (Constructor description)
104
	 * !ToDo (Constructor description)
92
	 * 
105
	 * 
Lines 217-222 Link Here
217
		return (CollectionProperty) getProperty(TEST_STRINGS);
230
		return (CollectionProperty) getProperty(TEST_STRINGS);
218
	}
231
	}
219
232
233
	public boolean isEqualsType() {
234
		return (getTestType() & EQUALS) > 0;
235
	}
236
220
	public boolean isContainsType() {
237
	public boolean isContainsType() {
221
		return (getTestType() & CONTAINS) > 0;
238
		return (getTestType() & CONTAINS) > 0;
222
	}
239
	}
Lines 230-243 Link Here
230
	}
247
	}
231
248
232
	public void setToContainsType() {
249
	public void setToContainsType() {
233
		setTestType((getTestType() | CONTAINS) & (~MATCH));
250
		setTestType((getTestType() | CONTAINS) & ~ (MATCH | EQUALS));
234
	}
251
	}
235
252
236
	public void setToMatchType() {
253
	public void setToMatchType() {
237
		setTestType((getTestType() | MATCH) & (~CONTAINS));
254
		setTestType((getTestType() | MATCH) & ~(CONTAINS | EQUALS));
238
	}
255
	}
239
256
240
	public void setToNotType() {
257
	public void setToEqualsType() {
258
		setTestType((getTestType() | EQUALS) & ~(MATCH | CONTAINS));
259
	}
260
261
    public void setToNotType() {
241
		setTestType((getTestType() | NOT));
262
		setTestType((getTestType() | NOT));
242
	}
263
	}
243
264
Lines 294-326 Link Here
294
		result.setError(false);
315
		result.setError(false);
295
316
296
		boolean contains = isContainsType(); // do it once outside loop
317
		boolean contains = isContainsType(); // do it once outside loop
297
		boolean debugEnabled = log.isDebugEnabled();
318
        boolean equals = isEqualsType();
319
        boolean debugEnabled = log.isDebugEnabled();
298
		if (debugEnabled){
320
		if (debugEnabled){
299
			log.debug("Type:" + (contains?"Contains":"Match") + (not? "(not)": ""));
321
			log.debug("Type:" + (contains?"Contains":"Match") + (not? "(not)": ""));
300
		}
322
		}
301
		
323
302
		try {
324
        try {
303
			// Get the Matcher for this thread
325
			// Get the Matcher for this thread
304
			Perl5Matcher localMatcher = (Perl5Matcher) matcher.get();
326
			Perl5Matcher localMatcher = (Perl5Matcher) matcher.get();
305
			PropertyIterator iter = getTestStrings().iterator();
327
			PropertyIterator iter = getTestStrings().iterator();
306
			while (iter.hasNext()) {
328
			while (iter.hasNext()) {
307
				String stringPattern = iter.next().getStringValue();
329
				String stringPattern = iter.next().getStringValue();
308
				Pattern pattern = patternCache.getPattern(stringPattern, Perl5Compiler.READ_ONLY_MASK);
330
                boolean found;
309
				boolean found;
331
310
				if (contains) {
332
                if (equals) {
311
					found = localMatcher.contains(toCheck, pattern);
333
                    found = toCheck.equals(stringPattern);
312
				} else {
334
                } else {
313
					found = localMatcher.matches(toCheck, pattern);
335
                    Pattern pattern = patternCache.getPattern(stringPattern, Perl5Compiler.READ_ONLY_MASK);
314
				}
336
                    if (contains) {
315
				pass = not ? !found : found;
337
                        found = localMatcher.contains(toCheck, pattern);
338
                    } else {
339
                        found = localMatcher.matches(toCheck, pattern);
340
                    }
341
                }
342
                pass = not ? !found : found;
316
				if (!pass) {
343
				if (!pass) {
317
					if (debugEnabled){log.debug("Failed: "+pattern);}
344
                    String      failText = getFailText(stringPattern);
318
					result.setFailure(true);
345
319
					result.setFailureMessage(getFailText(stringPattern));
346
                    if (equals) {
347
                        failText += equalsComparisonText(toCheck, stringPattern);
348
                    }
349
                    log.info(failText);
350
                    result.setFailure(true);
351
					result.setFailureMessage(failText);
320
					break;
352
					break;
321
				}
353
				}
322
				if (debugEnabled){log.debug("Passed: "+pattern);}
354
				if (debugEnabled){log.debug("Passed: (" + getName() + ") /" + stringPattern);}
323
			}
355
                if (equals)
356
                    break;
357
            }
324
		} catch (MalformedCachePatternException e) {
358
		} catch (MalformedCachePatternException e) {
325
			result.setError(true);
359
			result.setError(true);
326
			result.setFailure(false);
360
			result.setFailure(false);
Lines 329-371 Link Here
329
		return result;
363
		return result;
330
	}
364
	}
331
365
332
	/**
366
    private static String trunc(final boolean right, final String str)
333
	 * Generate the failure reason from the TestType
367
    {
334
	 * 
368
        if (str.length() <= EQUALS_SECTION_DIFF_LEN)
335
	 * @param stringPattern
369
            return str;
336
	 * @return the message for the assertion report 
370
        else if (right)
337
	 */
371
            return str.substring(0, EQUALS_SECTION_DIFF_LEN) + EQUALS_DIFF_TRUNC;
338
	// TODO strings should be resources
372
        else
339
	private String getFailText(String stringPattern) {
373
            return EQUALS_DIFF_TRUNC + str.substring(str.length() - EQUALS_SECTION_DIFF_LEN, str.length());
340
		String text;
374
    }
341
		String what;
342
		if (ResponseAssertion.RESPONSE_DATA.equals(getTestField())) {
343
			what = "text";
344
		} else if (ResponseAssertion.RESPONSE_CODE.equals(getTestField())) {
345
			what = "code";
346
		} else if (ResponseAssertion.RESPONSE_MESSAGE.equals(getTestField())) {
347
			what = "message";
348
		} else // Assume it is the URL
349
		{
350
			what = "URL";
351
		}
352
		switch (getTestType()) {
353
		case CONTAINS:
354
			text = " expected to contain ";
355
			break;
356
		case NOT | CONTAINS:
357
			text = " expected not to contain ";
358
			break;
359
		case MATCH:
360
			text = " expected to match ";
361
			break;
362
		case NOT | MATCH:
363
			text = " expected not to match ";
364
			break;
365
		default:// should never happen...
366
			text = " expected something using ";
367
		}
368
375
369
		return "Test failed, " + what + text + "/" + stringPattern + "/";
376
    /**
370
	}
377
     *   Returns some helpful logging text to determine where equality between two strings
378
     * is broken, with one pointer working from the front of the strings and another working
379
     * backwards from the end.
380
     *
381
     * @param received      String received from sampler.
382
     * @param comparison    String specified for "equals" response assertion.
383
     * @return  Two lines of text separated by newlines, and then forward and backward pointers
384
     *      denoting first position of difference.
385
     */
386
    private static String equalsComparisonText(final String received, final String comparison)
387
    {
388
        final StringBuffer      text;
389
        int                     firstDiff;
390
        int                     lastRecDiff = -1;
391
        int                     lastCompDiff = -1;
392
        final int               recLength = received.length();
393
        final int               compLength = comparison.length();
394
        final int               minLength = Math.min(recLength, compLength);
395
        final String            startingEqSeq;
396
        String                  recDeltaSeq = "";
397
        String                  compDeltaSeq = "";
398
        String                  endingEqSeq = "";
399
        final StringBuffer      pad;
400
401
402
        text = new StringBuffer(Math.max(recLength, compLength) * 2);
403
        for (firstDiff = 0; firstDiff < minLength; firstDiff++)
404
            if (received.charAt(firstDiff) != comparison.charAt(firstDiff))
405
                break;
406
        if (firstDiff == 0)
407
            startingEqSeq = "";
408
        else
409
            startingEqSeq = trunc(false, received.substring(0, firstDiff));
410
411
        lastRecDiff = recLength - 1;
412
        lastCompDiff = compLength - 1;
413
414
        while ((lastRecDiff > firstDiff) && (lastCompDiff > firstDiff)
415
                && received.charAt(lastRecDiff) == comparison.charAt(lastCompDiff))
416
        {
417
            lastRecDiff--;
418
            lastCompDiff--;
419
        }
420
        endingEqSeq = trunc(true, received.substring(lastRecDiff + 1, recLength));
421
        if (endingEqSeq.length() == 0)
422
        {
423
            recDeltaSeq = trunc(true, received.substring(firstDiff, recLength));
424
            compDeltaSeq = trunc(true, comparison.substring(firstDiff, compLength));
425
        }
426
        else
427
        {
428
            recDeltaSeq = trunc(true, received.substring(firstDiff, lastRecDiff + 1));
429
            compDeltaSeq = trunc(true, comparison.substring(firstDiff, lastCompDiff + 1));
430
        }
431
        pad = new StringBuffer(Math.abs(recDeltaSeq.length() - compDeltaSeq.length()));
432
        for (int i = 0; i < pad.capacity(); i++)
433
            pad.append(' ');
434
        if (recDeltaSeq.length() > compDeltaSeq.length())
435
            compDeltaSeq += pad.toString();
436
        else
437
            recDeltaSeq += pad.toString();
438
439
        text.append('\n').append(RECEIVED_STR).append('\n');
440
        text.append(RECEIVED_STR);
441
        text.append(startingEqSeq);
442
        text.append(DIFF_DELTA_PRE);
443
        text.append(recDeltaSeq);
444
        text.append(DIFF_DELTA_POST);
445
        text.append(endingEqSeq);
446
        text.append('\n').append(COMPARISON_STR).append('\n');
447
        text.append(COMPARISON_STR);
448
        text.append(startingEqSeq);
449
        text.append(DIFF_DELTA_PRE);
450
        text.append(compDeltaSeq);
451
        text.append(DIFF_DELTA_POST);
452
        text.append(endingEqSeq);
453
        text.append('\n');
454
        return text.toString();
455
    }
456
457
//    public static void main(String[] args)
458
//    {
459
//        final String longA =
460
//"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
461
//        final String longZ =
462
//"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
463
//        String[][]  tests = new String[][] {
464
//            new String[] { "aaa", "zzz" },
465
//            new String[] { "aaa", "aaazzz" },
466
//            new String[] { "aaaz", "aaazzz" },
467
//            new String[] { "aaazzz", "aaaz" },
468
//            new String[] { "aaazzz", "aaabcdezzz" },
469
//
470
//                // all long delta
471
//            new String[] { longA, longZ },
472
//                // all long v. short delta
473
//            new String[] { longA, "yyy" },
474
//                // all long v. short delta
475
//            new String[] { "yyy", longA },
476
//
477
//                // long intial, long delta
478
//            new String[] { longA + longA, longA + longZ },
479
//                // long intial, long v. short delta
480
//            new String[] { longA + "yyy", longA + longZ },
481
//                // long intial, long v. short delta
482
//            new String[] { longA + longZ, longA + "yyy" },
483
//
484
//                // long intial, long delta, long final
485
//            new String[] { longA + longA + longZ, longA + longZ + longZ},
486
//                // long intial, long delta v. short delta, long final
487
//            new String[] { longA + longA + longZ, longA + "yyy" + longZ},
488
//                // long intial, long delta v. short delta, long final
489
//            new String[] { longA + "yyy" + longZ, longA + longZ}
490
//        };
491
//
492
//        for (int i = 0; i < tests.length; i++)
493
//        {
494
//            String[] test = tests[i];
495
//
496
//            System.out.println();
497
//            System.out.println(equalsComparisonText(test[0], test[1]));
498
//        }
499
//    }
500
501
    /**
502
     * Generate the failure reason from the TestType
503
     *
504
     * @param stringPattern
505
     * @return the message for the assertion report
506
     */
507
    // TODO strings should be resources
508
    private String getFailText(String stringPattern) {
509
        String text;
510
        String what;
511
        if (ResponseAssertion.RESPONSE_DATA.equals(getTestField())) {
512
            what = "text";
513
        } else if (ResponseAssertion.RESPONSE_CODE.equals(getTestField())) {
514
            what = "code";
515
        } else if (ResponseAssertion.RESPONSE_MESSAGE.equals(getTestField())) {
516
            what = "message";
517
        } else // Assume it is the URL
518
        {
519
            what = "URL";
520
        }
521
        switch (getTestType()) {
522
        case CONTAINS:
523
            text = " expected to contain ";
524
            break;
525
        case NOT | CONTAINS:
526
            text = " expected not to contain ";
527
            break;
528
        case MATCH:
529
            text = " expected to match ";
530
            break;
531
        case NOT | MATCH:
532
            text = " expected not to match ";
533
            break;
534
        case EQUALS:
535
            text = " expected to equal ";
536
            break;
537
        case NOT | EQUALS:
538
            text = " expected not to equal ";
539
            break;
540
        default:// should never happen...
541
            text = " expected something using ";
542
        }
543
544
        return "Test failed, (" + getName() + "): " + what + text + "/" + stringPattern + "/";
545
    }
371
}
546
}
(-)src/core/org/apache/jmeter/resources/messages.properties (+1 lines)
Lines 46-51 Link Here
46
assertion_code_resp=Response Code
46
assertion_code_resp=Response Code
47
assertion_contains=Contains
47
assertion_contains=Contains
48
assertion_matches=Matches
48
assertion_matches=Matches
49
assertion_equals=Equals
49
assertion_message_resp=Response Message
50
assertion_message_resp=Response Message
50
assertion_not=Not
51
assertion_not=Not
51
assertion_pattern_match_rules=Pattern Matching Rules
52
assertion_pattern_match_rules=Pattern Matching Rules
(-)src/core/org/apache/jmeter/util/JMeterVersion.java (-1 / +1 lines)
Lines 41-47 Link Here
41
	 * JMeterUtils This ensures that JMeterUtils always gets the correct
41
	 * JMeterUtils This ensures that JMeterUtils always gets the correct
42
	 * version, even if it is not re-compiled during the build.
42
	 * version, even if it is not re-compiled during the build.
43
	 */
43
	 */
44
	private static final String VERSION = "2.1.2";
44
	private static final String VERSION = "2.1.2.20060905";
45
45
46
	static final String COPYRIGHT = "Copyright (c) 1998-2006 The Apache Software Foundation";
46
	static final String COPYRIGHT = "Copyright (c) 1998-2006 The Apache Software Foundation";
47
47
(-)src/protocol/ldap/org/apache/jmeter/protocol/ldap/sampler/LDAPExtSampler.java (-51 / +223 lines)
Lines 17-36 Link Here
17
17
18
package org.apache.jmeter.protocol.ldap.sampler;
18
package org.apache.jmeter.protocol.ldap.sampler;
19
19
20
import java.util.Hashtable;
20
import java.util.*;
21
import java.util.Iterator;
21
import java.io.UnsupportedEncodingException;
22
import java.util.Map;
23
22
24
import javax.naming.NamingEnumeration;
23
import javax.naming.NamingEnumeration;
25
import javax.naming.NamingException;
24
import javax.naming.NamingException;
26
import javax.naming.directory.Attribute;
25
import javax.naming.directory.*;
27
import javax.naming.directory.Attributes;
28
import javax.naming.directory.BasicAttribute;
29
import javax.naming.directory.BasicAttributes;
30
import javax.naming.directory.DirContext;
31
import javax.naming.directory.InitialDirContext;
32
import javax.naming.directory.ModificationItem;
33
import javax.naming.directory.SearchResult;
34
26
35
import org.apache.jmeter.config.Argument;
27
import org.apache.jmeter.config.Argument;
36
import org.apache.jmeter.config.Arguments;
28
import org.apache.jmeter.config.Arguments;
Lines 44-49 Link Here
44
import org.apache.jmeter.testelement.property.PropertyIterator;
36
import org.apache.jmeter.testelement.property.PropertyIterator;
45
import org.apache.jmeter.testelement.property.StringProperty;
37
import org.apache.jmeter.testelement.property.StringProperty;
46
import org.apache.jmeter.testelement.property.TestElementProperty;
38
import org.apache.jmeter.testelement.property.TestElementProperty;
39
import org.apache.jmeter.util.JMeterUtils;
47
import org.apache.jorphan.logging.LoggingManager;
40
import org.apache.jorphan.logging.LoggingManager;
48
import org.apache.log.Logger;
41
import org.apache.log.Logger;
49
42
Lines 56-61 Link Here
56
49
57
    private static final Logger log = LoggingManager.getLoggerForClass();
50
    private static final Logger log = LoggingManager.getLoggerForClass();
58
51
52
    /** Signature start of response data generated by this sample. */
53
    public static final String LDAPANSWER = "<ldapanswer>";
54
    public static final String LDAPANSWER_END = LDAPANSWER.replaceFirst("<", "</");
55
59
	public final static String SERVERNAME = "servername"; // $NON-NLS-1$
56
	public final static String SERVERNAME = "servername"; // $NON-NLS-1$
60
57
61
	public final static String PORT = "port"; // $NON-NLS-1$
58
	public final static String PORT = "port"; // $NON-NLS-1$
Lines 125-139 Link Here
125
    // TODO replace these with ThreadLocal
122
    // TODO replace these with ThreadLocal
126
	private static Hashtable ldapConnections = new Hashtable();
123
	private static Hashtable ldapConnections = new Hashtable();
127
124
128
	private static Hashtable ldapContexts = new Hashtable();
125
	private static Hashtable    ldapContexts = new Hashtable();
126
    protected static final int MAX_SORTED_RESULTS = JMeterUtils.getPropDefault("ldapsampler.max_sorted_results", 1000);
127
    public static final String OBJECT_SCOPE_STR = "object";
128
    public static final String ONELEVEL_SCOPE_STR = "onelevel";
129
    public static final String SUBTREE_SCOPE_STR = "subtree";
129
130
130
	/***************************************************************************
131
	 * !ToDo (Constructor description)
132
	 **************************************************************************/
133
	public LDAPExtSampler() {
134
	}
135
131
136
	/***************************************************************************
132
    /***************************************************************************
133
     * !ToDo (Constructor description)
134
     **************************************************************************/
135
    public LDAPExtSampler() {
136
    }
137
138
    /***************************************************************************
137
	 * Gets the username attribute of the LDAP object
139
	 * Gets the username attribute of the LDAP object
138
	 * 
140
	 * 
139
	 * @return The username
141
	 * @return The username
Lines 511-517 Link Here
511
			if ("add".equals(item.getOpcode())) { // $NON-NLS-1$
513
			if ("add".equals(item.getOpcode())) { // $NON-NLS-1$
512
				mods[count] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr);
514
				mods[count] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr);
513
			} else {
515
			} else {
514
				if ("delete".equals(item.getOpcode())) { // $NON-NLS-1$
516
				if ("delete".equals(item.getOpcode()) || "remove".equals(item.getOpcode())) { // $NON-NLS-1$
515
					mods[count] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr);
517
					mods[count] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr);
516
				} else {
518
				} else {
517
					mods[count] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
519
					mods[count] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
Lines 681-687 Link Here
681
	 * @return !ToDo (Return description)
683
	 * @return !ToDo (Return description)
682
	 **************************************************************************/
684
	 **************************************************************************/
683
	public SampleResult sample(Entry e) {
685
	public SampleResult sample(Entry e) {
684
		String responseData = "<ldapanswer>";
686
		String responseData = LDAPANSWER;
685
		SampleResult res = new SampleResult();
687
		SampleResult res = new SampleResult();
686
		res.setResponseData("successfull".getBytes());
688
		res.setResponseData("successfull".getBytes());
687
		res.setResponseMessage("Success");
689
		res.setResponseMessage("Success");
Lines 761-799 Link Here
761
				responseData = responseData + "<newdn>" + getPropertyAsString(NEWDN) + "</newdn></operation>";
763
				responseData = responseData + "<newdn>" + getPropertyAsString(NEWDN) + "</newdn></operation>";
762
				renameTest(temp_client, dirContext, res);
764
				renameTest(temp_client, dirContext, res);
763
			} else if (getPropertyAsString(TEST).equals(SEARCHBASE)) {
765
			} else if (getPropertyAsString(TEST).equals(SEARCHBASE)) {
764
				res.setSamplerData("Search with filter " + getPropertyAsString(SEARCHFILTER));
766
                final StringBuffer      sb = new StringBuffer(2 * 1024);
765
				responseData = responseData + "<operation><opertype>search</opertype>";
767
                final String            scopeStr = getPropertyAsString(SCOPE);
766
				responseData = responseData + "<searchfilter>" + getPropertyAsString(SEARCHFILTER) + "</searchfilter>";
768
                final int               scope;
767
				responseData = responseData + "<searchbase>" + getPropertyAsString(SEARCHBASE) + ","
769
768
						+ getPropertyAsString(ROOTDN) + "</searchbase>";
770
                res.setSamplerData("Search with filter " + getPropertyAsString(SEARCHFILTER));
769
				responseData = responseData + "<scope>" + getPropertyAsString(SCOPE) + "</scope>";
771
                sb.append(responseData);
770
				responseData = responseData + "<countlimit>" + getPropertyAsString(COUNTLIM) + "</countlimit>";
772
                sb.append("<operation>");
771
				responseData = responseData + "<timelimit>" + getPropertyAsString(TIMELIM) + "</timelimit>";
773
                writeSearchResponseHeader(sb);
772
				responseData = responseData + "</operation><searchresult>";
774
                if (OBJECT_SCOPE_STR.equals(scopeStr))
775
                    scope = SearchControls.OBJECT_SCOPE;
776
                else if (ONELEVEL_SCOPE_STR.equals(scopeStr))
777
                    scope = SearchControls.ONELEVEL_SCOPE;
778
                else if (SUBTREE_SCOPE_STR.equals(scopeStr))
779
                    scope = SearchControls.SUBTREE_SCOPE;
780
                else
781
                        // for backwards compatibility
782
                    scope = getPropertyAsInt(SCOPE);
783
773
                res.sampleStart();
784
                res.sampleStart();
774
                NamingEnumeration srch = temp_client.searchTest(dirContext, getPropertyAsString(SEARCHBASE), getPropertyAsString(SEARCHFILTER),
785
                NamingEnumeration srch = temp_client.searchTest(dirContext, getPropertyAsString(SEARCHBASE), getPropertyAsString(SEARCHFILTER),
775
                        getPropertyAsInt(SCOPE), getPropertyAsLong(COUNTLIM), getPropertyAsInt(TIMELIM),
786
                        scope, getPropertyAsLong(COUNTLIM), getPropertyAsInt(TIMELIM),
776
                        getRequestAttributes(getPropertyAsString(ATTRIBS)), getPropertyAsBoolean(RETOBJ),
787
                        getRequestAttributes(getPropertyAsString(ATTRIBS)), getPropertyAsBoolean(RETOBJ),
777
                        getPropertyAsBoolean(DEREF));
788
                        getPropertyAsBoolean(DEREF));
778
                res.sampleEnd();
789
                res.sampleEnd();
779
				while (srch.hasMore()) {
790
                writeSearchResults(sb, srch);
780
                    SearchResult sr = (SearchResult) srch.next();
791
                sb.append("</operation>");
781
					responseData = responseData + "<dn>" + sr.getName() + "," + getPropertyAsString(SEARCHBASE) + ","
792
                responseData = sb.toString();
782
							+ getRootdn() + "</dn>";
793
            }
783
					responseData = responseData + "<returnedattr>" + sr.getAttributes().size() + "</returnedattr>";
784
                    NamingEnumeration attrlist = sr.getAttributes().getIDs();
785
					while (attrlist.hasMore()) {
786
						String iets = (String) attrlist.next();
787
						responseData = responseData + "<attribute><attributename>" + iets
788
								+ "</attributename>";
789
						responseData = responseData
790
								+ "<attributevalue>"
791
								+ sr.getAttributes().get(iets).toString().substring(
792
										iets.length() + 2) + "</attributevalue></attribute>";
793
					}
794
				}
795
				responseData = responseData + "</searchresult></operation>";
796
			}
797
794
798
		} catch (NamingException ex) {
795
		} catch (NamingException ex) {
799
			String returnData = ex.toString();
796
			String returnData = ex.toString();
Lines 818-827 Link Here
818
		return res;
815
		return res;
819
	}
816
	}
820
817
821
	public void testStarted() {
818
    public void writeSearchResponseHeader(final StringBuffer sb)
822
		testStarted("");
819
    {
823
	}
820
        String          scopeStr = getPropertyAsString(SCOPE);
824
821
822
        sb.append("<opertype>search</opertype>");
823
        sb.append("<searchfilter>").append(getPropertyAsString(SEARCHFILTER)).append("</searchfilter>");
824
        sb.append("<searchbase>").append(getPropertyAsString(SEARCHBASE)).append(",")
825
                .append(getPropertyAsString(ROOTDN)).append("</searchbase>");
826
        if (scopeStr.equals("0"))
827
            scopeStr = OBJECT_SCOPE_STR;
828
        else if (scopeStr.equals("1"))
829
            scopeStr = ONELEVEL_SCOPE_STR;
830
        else if (scopeStr.equals("2"))
831
            scopeStr = SUBTREE_SCOPE_STR;
832
        sb.append("<scope>").append(scopeStr).append("</scope>");
833
        sb.append("<countlimit>").append(getPropertyAsString(COUNTLIM)).append("</countlimit>");
834
        sb.append("<timelimit>").append(getPropertyAsString(TIMELIM)).append("</timelimit>");
835
    }
836
837
    /**
838
     *   Write out search results in a stable order (including order of all subelements which might
839
     * be reordered like attributes and their values) so that simple textual comparison can be done,
840
     * unless the number of results exceeds {@link #MAX_SORTED_RESULTS} in which case just stream
841
     * the results out without sorting.
842
     */
843
    public void writeSearchResults(final StringBuffer sb, final NamingEnumeration srch)
844
            throws NamingException
845
    {
846
        final ArrayList         sortedResults = new ArrayList(MAX_SORTED_RESULTS);
847
        boolean                 abandonedSort;
848
849
        sb.append("<searchresults>");
850
        // read all sortedResults into memory so we can guarantee ordering
851
        while (srch.hasMore() && (sortedResults.size() < MAX_SORTED_RESULTS)) {
852
            final SearchResult    sr = (SearchResult) srch.next();
853
854
            sortedResults.add(sr);
855
        }
856
857
        abandonedSort = (sortedResults.size() >= MAX_SORTED_RESULTS);
858
        if (!abandonedSort)
859
        {
860
            Collections.sort(sortedResults, new Comparator()
861
            {
862
                public int compare(Object o1, Object o2)
863
                {
864
                    String      nm1 = ((SearchResult) o1).getName();
865
                    String      nm2 = ((SearchResult) o2).getName();
866
867
                    if (nm1 == null)
868
                        nm1 = "";
869
                    if (nm2 == null)
870
                        nm2 = "";
871
                    return nm1.compareTo(nm2);
872
                }
873
            });
874
        }
875
876
        for (Iterator it = sortedResults.iterator(); it.hasNext();)
877
        {
878
            final SearchResult  sr = (SearchResult) it.next();
879
            writeSearchResult(sr, sb);
880
        }
881
882
        if (abandonedSort)
883
        {
884
                // if abonded sort because there were too many items, then read the
885
                //  rest of the results now...
886
            while (srch.hasMore()) {
887
                final SearchResult    sr = (SearchResult) srch.next();
888
889
                writeSearchResult(sr, sb);
890
            }
891
        }
892
        sb.append("</searchresults>");
893
    }
894
895
    private void writeSearchResult(final SearchResult sr, final StringBuffer responseData)
896
            throws NamingException
897
    {
898
        String              srName = sr.getName();
899
        final Attributes    attrs = sr.getAttributes();
900
        final ArrayList     sortedAttrs;
901
        final String        searchBase = getPropertyAsString(SEARCHBASE);
902
        final String        rootDn = getRootdn();
903
904
        responseData.append("<searchresult>");
905
        responseData.append("<dn>");
906
        if (!srName.endsWith(searchBase))
907
        {
908
            if (srName.length() > 0)
909
                srName = srName + ',';
910
            srName = srName + searchBase;
911
        }
912
        if ((rootDn.length() > 0) && !srName.endsWith(rootDn))
913
        {
914
            if (srName.length() > 0)
915
                srName = srName + ',';
916
            srName = srName + rootDn;
917
        }
918
        responseData.append(srName);
919
        responseData.append("</dn>");
920
        responseData.append("<returnedattr>").append(attrs.size()).append("</returnedattr>");
921
        sortedAttrs = new ArrayList(attrs.size());
922
        for (NamingEnumeration en = attrs.getAll(); en.hasMore(); )
923
        {
924
            final Attribute     attr = (Attribute) en.next();
925
926
            sortedAttrs.add(attr);
927
        }
928
        Collections.sort(sortedAttrs, new Comparator()
929
        {
930
            public int compare(Object o1, Object o2)
931
            {
932
                String      nm1 = ((Attribute) o1).getID();
933
                String      nm2 = ((Attribute) o2).getID();
934
935
                return nm1.compareTo(nm2);
936
            }
937
        });
938
        for (Iterator ait = sortedAttrs.iterator(); ait.hasNext();)
939
        {
940
            final Attribute     attr = (Attribute) ait.next();
941
942
            responseData.append("<attribute><attributename>").append(attr.getID()).append("</attributename>");
943
            responseData.append("<attributevalue>");
944
            if (attr.size() == 1)
945
                responseData.append(getWriteValue(attr.get()));
946
            else
947
            {
948
                final ArrayList     sortedVals = new ArrayList(attr.size());
949
                boolean             first = true;
950
951
                for (NamingEnumeration ven = attr.getAll(); ven.hasMore(); )
952
                {
953
                    final Object    value = getWriteValue(ven.next());
954
955
                    sortedVals.add(value.toString());
956
                }
957
958
                Collections.sort(sortedVals);
959
                
960
                for (Iterator vit = sortedVals.iterator(); vit.hasNext();)
961
                {
962
                    final String    value = (String) vit.next();
963
964
                    if (first)
965
                        first = false;
966
                    else
967
                        responseData.append(", ");
968
                    responseData.append(value);
969
                }
970
            }
971
            responseData.append("</attributevalue></attribute>");
972
        }
973
        responseData.append("</searchresult>");
974
    }
975
976
    private String getWriteValue(final Object value)
977
    {
978
        if (value instanceof String)
979
            // assume it's senstive data
980
            return (String)value;
981
        else if (value instanceof byte[])
982
            try
983
            {
984
                return new String((byte[])value, "UTF-8");
985
            }
986
            catch (UnsupportedEncodingException e)
987
            {
988
                log.error("this can't happen: UTF-8 character encoding not supported", e);
989
            }
990
        return value.toString();
991
    }
992
993
    public void testStarted() {
994
        testStarted("");
995
    }
996
825
	public void testEnded() {
997
	public void testEnded() {
826
		testEnded("");
998
		testEnded("");
827
	}
999
	}

Return to bug 40369