summaryrefslogtreecommitdiff
path: root/qpid/java/client/src/test/java/org/apache/qpid/client/DeliveryCountTrackerTest.java
blob: 2f3a186d825bedb3c25436d565fd54a82f5cd7e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package org.apache.qpid.client;

import java.util.ArrayList;

import junit.framework.TestCase;

public class DeliveryCountTrackerTest extends TestCase
{
    private DeliveryCountTracker _tracker;
    private final int CAPACITY=50;

    protected void setUp()
    {
        _tracker = new DeliveryCountTracker(CAPACITY);
    }

    /**
     * Test the LRU based eviction policy of the tracker. Both the process of tracking new sightings of a given
     * JMSMessageID and retrieving the existing count will involve accessing an existing record and making it 
     * the most recently accessed. Commit/Rollback/Recover should remove any messages that can't be seen again
     * due to consumption or rejection. Any other messages must be evicted by LRU policy as and when necessary
     * to make way for new entries.
     * 
     * Test this by validating that upon tracking one more message than the capacity, the first message count 
     * is lost. Then access the second message count and insert a further new message occurrence. Verify the 
     * third message count is removed and not the second message count.
     */
    public void testLRUeviction()
    {
        long id;

        for(id=1; id <= CAPACITY + 1; id ++)
        {
            _tracker.recordMessage(String.valueOf(id), id);
        }
        
        assertEquals("Count was not as expected. First delivery tag " +
        		"should have been evicted already:", _tracker.getDeliveryCount(1L), 0L);
        
        //Retrieve second delivery tag count, ensure it is not zero.
        //This will also make it the most recently accessed record.
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(2L), 1L);
        
        //Add a new record, check that tag 2 remains and tag 3 was evicted.
        _tracker.recordMessage(String.valueOf(id), id);
        assertEquals("Count was not as expected. Second delivery tag " +
                "should NOT have been evicted already:", _tracker.getDeliveryCount(2L), 1L);
        assertEquals("Count was not as expected. Third delivery tag " +
                "should have been evicted already:", _tracker.getDeliveryCount(3L), 0L);
    }

    /**
     * Test that once it is known a record can never be useful again it can be successfully removed
     * from the records to allow room for new records without causing eviction of information that 
     * could still be useful.
     * 
     * Fill the tracker with records, ensure the counts are correct and then delete them, and ensure the
     * counts get reset.
     */
    public void testMessageRecordRemoval()
    {
        long id;

        for(id=1 ; id <= CAPACITY; id ++)
        {
            _tracker.recordMessage(String.valueOf(id), id);
        }

        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(1L), 1L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY/2), 1L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY-1), 1L);
        
        //remove records for first deliveryTag, ensure the others remain as expected
        _tracker.removeRecordsForMessage(1L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(1L), 0L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY/2), 1L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY-1), 1L);
        
        //remove records for next deliveryTag, ensure the others remain as expected
        _tracker.removeRecordsForMessage(CAPACITY/2);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(1L), 0L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY/2), 0L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY-1), 1L);
        
        //remove records for next deliveryTag, ensure the others remain as expected
        _tracker.removeRecordsForMessage(CAPACITY-1);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(1L), 0L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY/2), 0L);
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY-1), 0L);
        
        //ensure records for last deliveryTag is still as expected
        assertEquals("Count was not as expected.", _tracker.getDeliveryCount(CAPACITY), 1L);
    }
    
    /**
     * Test that counts are accurately incremented and associated with the new deliveryTag when
     * a message with the same JMSMessageID is encountered again, also ensuring that record of
     * the count is no longer returned via the old deliveryTag
     */
    public void testCounting()
    {
        long id;

        for(id=1 ; id <= CAPACITY; id ++)
        {
            _tracker.recordMessage(String.valueOf(id), id);
        }
        
        //verify all counts are currently 1
        ArrayList<Long> exclusions = new ArrayList<Long>();
        verifyCounts(1,exclusions, CAPACITY);
        
        //Gather some of the existing JMSMessageIDs and create new deliveryTags for them, which can
        //be used to represent receiving the same message again.
        String msgId1 = String.valueOf(1L);
        long newTag1 = id;
        String msgId2 = String.valueOf(CAPACITY/2);
        long newTag2 = ++id;
        String msgId3 = String.valueOf(CAPACITY);
        long newTag3 = ++id;
        _tracker.recordMessage(String.valueOf(msgId1), newTag1);
        _tracker.recordMessage(String.valueOf(msgId2), newTag2);
        _tracker.recordMessage(String.valueOf(msgId3), newTag3);
        
        //Now check the updated values returned are as expected. 
        
        //entries for delivery tags with value 1,CAPACITY/2,CAPACITY should have just been removed 
        //because new delivery tags associated with the same JMSMessageID were just recorded.
        assertEquals("Count was not as expected.", 0L, _tracker.getDeliveryCount(1));
        assertEquals("Count was not as expected.", 0L, _tracker.getDeliveryCount(CAPACITY/2));
        assertEquals("Count was not as expected.", 0L, _tracker.getDeliveryCount(CAPACITY));
        
        //The count for the 'redelivered' messages with new deliveryTag should have increased. 
        assertEquals("Count was not as expected.", 2L, _tracker.getDeliveryCount(newTag1));
        assertEquals("Count was not as expected.", 2L, _tracker.getDeliveryCount(newTag2));
        assertEquals("Count was not as expected.", 2L, _tracker.getDeliveryCount(newTag3));
        
        //all the other delivery tags should remain at 1:
        exclusions.add(1L);
        exclusions.add((long) CAPACITY/2);
        exclusions.add((long) CAPACITY);
        exclusions.add(newTag1);
        exclusions.add(newTag2);
        exclusions.add(newTag3);
        verifyCounts(1,exclusions, CAPACITY+3);
    }
    
    private void verifyCounts(long expectedValue, ArrayList<Long> excludeFromCheck, long numValues)
    {
        for(long id=1 ; id <= numValues; id ++)
        {
            if (!excludeFromCheck.contains(id))
            {
                assertEquals("Count was not as expected for id '" + id + "'.", 1L, _tracker.getDeliveryCount(id));
            }
        }
    }
}