2f838b39b215d33dabf4b146f7889ccf8ce3eea4
[notmuch] / test / T590-thread-breakage.sh
1 #!/usr/bin/env bash
2 #
3 # Copyright (c) 2016 Daniel Kahn Gillmor
4 #
5
6 test_description='thread breakage during reindexing
7
8 notmuch uses ghost documents to track messages we have seen references
9 to but have never seen.  Regardless of the order of delivery, message
10 deletion, and reindexing, the list of ghost messages for a given
11 stored corpus should not vary, so that threads can be reassmebled
12 cleanly.
13
14 In practice, we accept a small amount of variation (and therefore
15 traffic pattern metadata leakage to be stored in the index) for the
16 sake of efficiency.
17
18 This test also embeds some subtests to ensure that indexing actually
19 works properly and attempted fixes to threading issues do not break
20 the expected contents of the index.'
21
22 . ./test-lib.sh || exit 1
23
24 message_a() {
25     mkdir -p ${MAIL_DIR}/cur
26     cat > ${MAIL_DIR}/cur/a <<EOF
27 Subject: First message
28 Message-ID: <a@example.net>
29 From: Alice <alice@example.net>
30 To: Bob <bob@example.net>
31 Date: Thu, 31 Mar 2016 20:10:00 -0400
32
33 This is the first message in the thread.
34 Apple
35 EOF
36 }
37
38 message_b() {
39     mkdir -p ${MAIL_DIR}/cur
40     cat > ${MAIL_DIR}/cur/b <<EOF
41 Subject: Second message
42 Message-ID: <b@example.net>
43 In-Reply-To: <a@example.net>
44 References: <a@example.net>
45 From: Bob <bob@example.net>
46 To: Alice <alice@example.net>
47 Date: Thu, 31 Mar 2016 20:15:00 -0400
48
49 This is the second message in the thread.
50 Banana
51 EOF
52 }
53
54
55 test_content_count() {
56     test_begin_subtest "${3:-looking for $2 instance of '$1'}"
57     count=$(notmuch count --output=threads "$1")
58     test_expect_equal "$count" "$2"
59 }
60
61 test_thread_count() {
62     test_begin_subtest "${2:-Expecting $1 thread(s)}"
63     count=$(notmuch count --output=threads)
64     test_expect_equal "$count" "$1"
65 }
66
67 test_ghost_count() {
68     test_begin_subtest "${2:-Expecting $1 ghosts(s)}"
69     ghosts=$(../ghost-report ${MAIL_DIR}/.notmuch/xapian)
70     test_expect_equal "$ghosts" "$1"
71 }
72
73 notmuch new >/dev/null
74
75 test_thread_count 0 'There should be no threads initially'
76 test_ghost_count 0 'There should be no ghosts initially'
77
78 message_a
79 notmuch new >/dev/null
80 test_thread_count 1 'One message in: one thread'
81 test_content_count apple 1
82 test_content_count banana 0
83 test_ghost_count 0
84
85 message_b
86 notmuch new >/dev/null
87 test_thread_count 1 'Second message in the same thread: one thread'
88 test_content_count apple 1
89 test_content_count banana 1
90 test_ghost_count 0
91
92 rm -f ${MAIL_DIR}/cur/a
93 notmuch new >/dev/null
94 test_thread_count 1 'First message removed: still only one thread'
95 test_content_count apple 0
96 test_content_count banana 1
97 test_begin_subtest 'should be one ghost after first message removed'
98 test_subtest_known_broken
99 ghosts=$(../ghost-report ${MAIL_DIR}/.notmuch/xapian)
100 test_expect_equal "$ghosts" "1"
101
102 message_a
103 notmuch new >/dev/null
104 # this is known to fail (it shows 2 threads) because no "ghost
105 # message" was created for message A when it was removed from the
106 # index, despite message B still pointing to it.
107 test_begin_subtest 'First message reappears: should return to the same thread'
108 test_subtest_known_broken
109 count=$(notmuch count --output=threads)
110 test_expect_equal "$count" "1"
111 test_content_count apple 1
112 test_content_count banana 1
113 test_ghost_count 0
114
115 rm -f ${MAIL_DIR}/cur/b
116 notmuch new >/dev/null
117 test_thread_count 1 'Removing second message: still only one thread'
118 test_content_count apple 1
119 test_content_count banana 0
120 test_ghost_count 0 'No ghosts should remain after deletion of second message'
121
122 rm -f ${MAIL_DIR}/cur/a
123 notmuch new >/dev/null
124 test_thread_count 0 'All messages gone: no threads'
125 test_content_count apple 0
126 test_content_count banana 0
127 test_ghost_count 0
128
129 test_done