1 #include <gtest/gtest.h>
2
3 #include "node-inl.h"
4
5 #include <algorithm>
6 #include <memory>
7 #include <mutex>
8
9 using mediaprovider::fuse::dirhandle;
10 using mediaprovider::fuse::handle;
11 using mediaprovider::fuse::node;
12 using mediaprovider::fuse::NodeTracker;
13
14 // Listed as a friend class to struct node so it can observe implementation
15 // details if required. The only implementation detail that is worth writing
16 // tests around at the moment is the reference count.
17 class NodeTest : public ::testing::Test {
18 public:
NodeTest()19 NodeTest() : tracker_(NodeTracker(&lock_)) {}
20
GetRefCount(node * node)21 uint32_t GetRefCount(node* node) { return node->refcount_; }
22
23 std::recursive_mutex lock_;
24 NodeTracker tracker_;
25
26 // Forward destruction here, as NodeTest is a friend class.
destroy(node * node)27 static void destroy(node* node) { delete node; }
28
acquire(node * node)29 static void acquire(node* node) { node->Acquire(); }
30
31 typedef std::unique_ptr<node, decltype(&NodeTest::destroy)> unique_node_ptr;
32
CreateNode(node * parent,const std::string & path)33 unique_node_ptr CreateNode(node* parent, const std::string& path) {
34 return unique_node_ptr(node::Create(parent, path, &lock_, &tracker_), &NodeTest::destroy);
35 }
36 };
37
TEST_F(NodeTest,TestCreate)38 TEST_F(NodeTest, TestCreate) {
39 unique_node_ptr node = CreateNode(nullptr, "/path");
40
41 ASSERT_EQ("/path", node->GetName());
42 ASSERT_EQ(1, GetRefCount(node.get()));
43 ASSERT_FALSE(node->HasCachedHandle());
44 }
45
TEST_F(NodeTest,TestCreate_withParent)46 TEST_F(NodeTest, TestCreate_withParent) {
47 unique_node_ptr parent = CreateNode(nullptr, "/path");
48 ASSERT_EQ(1, GetRefCount(parent.get()));
49
50 // Adding a child to a parent node increments its refcount.
51 unique_node_ptr child = CreateNode(parent.get(), "subdir");
52 ASSERT_EQ(2, GetRefCount(parent.get()));
53
54 // Make sure the node has been added to the parents list of children.
55 ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", false /* acquire */));
56 ASSERT_EQ(1, GetRefCount(child.get()));
57 }
58
TEST_F(NodeTest,TestRelease)59 TEST_F(NodeTest, TestRelease) {
60 node* node = node::Create(nullptr, "/path", &lock_, &tracker_);
61 acquire(node);
62 acquire(node);
63 ASSERT_EQ(3, GetRefCount(node));
64
65 ASSERT_FALSE(node->Release(1));
66 ASSERT_EQ(2, GetRefCount(node));
67
68 // A Release that makes refcount go negative should be a no-op.
69 ASSERT_FALSE(node->Release(10000));
70 ASSERT_EQ(2, GetRefCount(node));
71
72 // Finally, let the refcount go to zero.
73 ASSERT_TRUE(node->Release(2));
74 }
75
TEST_F(NodeTest,TestRenameWithName)76 TEST_F(NodeTest, TestRenameWithName) {
77 unique_node_ptr parent = CreateNode(nullptr, "/path");
78
79 unique_node_ptr child = CreateNode(parent.get(), "subdir");
80 ASSERT_EQ(2, GetRefCount(parent.get()));
81 ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", false /* acquire */));
82
83 child->Rename("subdir_new", parent.get());
84
85 ASSERT_EQ(2, GetRefCount(parent.get()));
86 ASSERT_EQ(nullptr, parent->LookupChildByName("subdir", false /* acquire */));
87 ASSERT_EQ(child.get(), parent->LookupChildByName("subdir_new", false /* acquire */));
88
89 ASSERT_EQ("/path/subdir_new", child->BuildPath());
90 ASSERT_EQ(1, GetRefCount(child.get()));
91 }
92
TEST_F(NodeTest,TestRenameWithParent)93 TEST_F(NodeTest, TestRenameWithParent) {
94 unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
95 unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
96
97 unique_node_ptr child = CreateNode(parent1.get(), "subdir");
98 ASSERT_EQ(2, GetRefCount(parent1.get()));
99 ASSERT_EQ(child.get(), parent1->LookupChildByName("subdir", false /* acquire */));
100
101 child->Rename("subdir", parent2.get());
102 ASSERT_EQ(1, GetRefCount(parent1.get()));
103 ASSERT_EQ(nullptr, parent1->LookupChildByName("subdir", false /* acquire */));
104
105 ASSERT_EQ(2, GetRefCount(parent2.get()));
106 ASSERT_EQ(child.get(), parent2->LookupChildByName("subdir", false /* acquire */));
107
108 ASSERT_EQ("/path2/subdir", child->BuildPath());
109 ASSERT_EQ(1, GetRefCount(child.get()));
110 }
111
TEST_F(NodeTest,TestRenameWithNameAndParent)112 TEST_F(NodeTest, TestRenameWithNameAndParent) {
113 unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
114 unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
115
116 unique_node_ptr child = CreateNode(parent1.get(), "subdir");
117 ASSERT_EQ(2, GetRefCount(parent1.get()));
118 ASSERT_EQ(child.get(), parent1->LookupChildByName("subdir", false /* acquire */));
119
120 child->Rename("subdir_new", parent2.get());
121 ASSERT_EQ(1, GetRefCount(parent1.get()));
122 ASSERT_EQ(nullptr, parent1->LookupChildByName("subdir", false /* acquire */));
123 ASSERT_EQ(nullptr, parent1->LookupChildByName("subdir_new", false /* acquire */));
124
125 ASSERT_EQ(2, GetRefCount(parent2.get()));
126 ASSERT_EQ(child.get(), parent2->LookupChildByName("subdir_new", false /* acquire */));
127
128 ASSERT_EQ("/path2/subdir_new", child->BuildPath());
129 ASSERT_EQ(1, GetRefCount(child.get()));
130 }
131
TEST_F(NodeTest,TestBuildPath)132 TEST_F(NodeTest, TestBuildPath) {
133 unique_node_ptr parent = CreateNode(nullptr, "/path");
134 ASSERT_EQ("/path", parent->BuildPath());
135
136 unique_node_ptr child = CreateNode(parent.get(), "subdir");
137 ASSERT_EQ("/path/subdir", child->BuildPath());
138
139 unique_node_ptr child2 = CreateNode(parent.get(), "subdir2");
140 ASSERT_EQ("/path/subdir2", child2->BuildPath());
141
142 unique_node_ptr subchild = CreateNode(child2.get(), "subsubdir");
143 ASSERT_EQ("/path/subdir2/subsubdir", subchild->BuildPath());
144 }
145
TEST_F(NodeTest,TestSetDeleted)146 TEST_F(NodeTest, TestSetDeleted) {
147 unique_node_ptr parent = CreateNode(nullptr, "/path");
148 unique_node_ptr child = CreateNode(parent.get(), "subdir");
149
150 ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", false /* acquire */));
151 child->SetDeleted();
152 ASSERT_EQ(nullptr, parent->LookupChildByName("subdir", false /* acquire */));
153 }
154
TEST_F(NodeTest,DeleteTree)155 TEST_F(NodeTest, DeleteTree) {
156 unique_node_ptr parent = CreateNode(nullptr, "/path");
157
158 // This is the tree that we intend to delete.
159 node* child = node::Create(parent.get(), "subdir", &lock_, &tracker_);
160 node::Create(child, "s1", &lock_, &tracker_);
161 node* subchild2 = node::Create(child, "s2", &lock_, &tracker_);
162 node::Create(subchild2, "sc2", &lock_, &tracker_);
163
164 ASSERT_EQ(child, parent->LookupChildByName("subdir", false /* acquire */));
165 node::DeleteTree(child);
166 ASSERT_EQ(nullptr, parent->LookupChildByName("subdir", false /* acquire */));
167 }
168
TEST_F(NodeTest,LookupChildByName_empty)169 TEST_F(NodeTest, LookupChildByName_empty) {
170 unique_node_ptr parent = CreateNode(nullptr, "/path");
171 unique_node_ptr child = CreateNode(parent.get(), "subdir");
172
173 ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", false /* acquire */));
174 ASSERT_EQ(nullptr, parent->LookupChildByName("", false /* acquire */));
175 }
176
TEST_F(NodeTest,LookupChildByName_refcounts)177 TEST_F(NodeTest, LookupChildByName_refcounts) {
178 unique_node_ptr parent = CreateNode(nullptr, "/path");
179 unique_node_ptr child = CreateNode(parent.get(), "subdir");
180
181 ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", false /* acquire */));
182 ASSERT_EQ(1, GetRefCount(child.get()));
183
184 ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", true /* acquire */));
185 ASSERT_EQ(2, GetRefCount(child.get()));
186 }
187
TEST_F(NodeTest,LookupAbsolutePath)188 TEST_F(NodeTest, LookupAbsolutePath) {
189 unique_node_ptr parent = CreateNode(nullptr, "/path");
190 unique_node_ptr child = CreateNode(parent.get(), "subdir");
191 unique_node_ptr child2 = CreateNode(parent.get(), "subdir2");
192 unique_node_ptr subchild = CreateNode(child2.get(), "subsubdir");
193
194 ASSERT_EQ(parent.get(), node::LookupAbsolutePath(parent.get(), "/path"));
195 ASSERT_EQ(parent.get(), node::LookupAbsolutePath(parent.get(), "/path/"));
196 ASSERT_EQ(nullptr, node::LookupAbsolutePath(parent.get(), "/path2"));
197
198 ASSERT_EQ(child.get(), node::LookupAbsolutePath(parent.get(), "/path/subdir"));
199 ASSERT_EQ(child.get(), node::LookupAbsolutePath(parent.get(), "/path/subdir/"));
200 // TODO(narayan): Are the two cases below intentional behaviour ?
201 ASSERT_EQ(child.get(), node::LookupAbsolutePath(parent.get(), "/path//subdir"));
202 ASSERT_EQ(child.get(), node::LookupAbsolutePath(parent.get(), "/path///subdir"));
203
204 ASSERT_EQ(child2.get(), node::LookupAbsolutePath(parent.get(), "/path/subdir2"));
205 ASSERT_EQ(child2.get(), node::LookupAbsolutePath(parent.get(), "/path/subdir2/"));
206
207 ASSERT_EQ(nullptr, node::LookupAbsolutePath(parent.get(), "/path/subdir3/"));
208
209 ASSERT_EQ(subchild.get(), node::LookupAbsolutePath(parent.get(), "/path/subdir2/subsubdir"));
210 ASSERT_EQ(nullptr, node::LookupAbsolutePath(parent.get(), "/path/subdir/subsubdir"));
211 }
212
TEST_F(NodeTest,AddDestroyHandle)213 TEST_F(NodeTest, AddDestroyHandle) {
214 unique_node_ptr node = CreateNode(nullptr, "/path");
215
216 handle* h = new handle(-1, new mediaprovider::fuse::RedactionInfo, true /* cached */);
217 node->AddHandle(h);
218 ASSERT_TRUE(node->HasCachedHandle());
219
220 node->DestroyHandle(h);
221 ASSERT_FALSE(node->HasCachedHandle());
222
223 // Should all crash the process as the handle is no longer associated with
224 // the node in question.
225 EXPECT_DEATH(node->DestroyHandle(h), "");
226 EXPECT_DEATH(node->DestroyHandle(nullptr), "");
227 std::unique_ptr<handle> h2(
228 new handle(-1, new mediaprovider::fuse::RedactionInfo, true /* cached */));
229 EXPECT_DEATH(node->DestroyHandle(h2.get()), "");
230 }
231
TEST_F(NodeTest,CaseInsensitive)232 TEST_F(NodeTest, CaseInsensitive) {
233 unique_node_ptr parent = CreateNode(nullptr, "/path");
234 unique_node_ptr mixed_child = CreateNode(parent.get(), "cHiLd");
235
236 node* upper_child = parent->LookupChildByName("CHILD", false /* acquire */);
237 node* lower_child = parent->LookupChildByName("child", false /* acquire */);
238
239 ASSERT_EQ(mixed_child.get(), lower_child);
240 ASSERT_EQ(mixed_child.get(), upper_child);
241 }
242