Browse code
merge branch 'user'
Showing 8 changed files
... | ... |
@@ -1,8 +1,9 @@ |
1 | 1 |
CXXFLAGS += -fPIC -fno-stack-protector -std=c++14 |
2 | 2 |
CFLAGS += -fPIC -fno-stack-protector |
3 | 3 |
|
4 |
-OBJS = dual_control.o request.o dual_control_integrate.o validator.o conversation.o |
|
5 |
-TESTS = dual_control_test validator_test conversation_test request_test |
|
4 |
+OBJS = dual_control.o request.o dual_control_integrate.o validator.o conversation.o user.o \ |
|
5 |
+ sys_unistd.o sys_pwd.o |
|
6 |
+TESTS = dual_control_test validator_test conversation_test request_test user_test |
|
6 | 7 |
TESTOBJS = $(patsubst %,%.o,$(TESTS)) |
7 | 8 |
SRCS := $(OBJS:.o=.cc) $(TESTOBJS:.o=.cc) |
8 | 9 |
|
9 | 10 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,35 @@ |
1 |
+/* Copyright (C) CJ Affiliate |
|
2 |
+ * |
|
3 |
+ * You may use, distribute and modify this code under the |
|
4 |
+ * terms of the GNU General Public License version 2 or |
|
5 |
+ * later. |
|
6 |
+ * |
|
7 |
+ * You should have received a copy of the license with this |
|
8 |
+ * file. If not, you will find a copy in the "LICENSE" file |
|
9 |
+ * at https://github.com/cjdev/dual-control. |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+#include "sys_pwd.h" |
|
13 |
+ |
|
14 |
+#include <pwd.h> |
|
15 |
+ |
|
16 |
+namespace |
|
17 |
+{ |
|
18 |
+class impl : public pwd_ifc |
|
19 |
+{ |
|
20 |
+public: |
|
21 |
+ int getpwnam_r (const char *user_name, passwd *out, char *buffer, |
|
22 |
+ size_t buffer_sz, passwd **result) |
|
23 |
+ { |
|
24 |
+ return ::getpwnam_r (user_name, out, buffer, buffer_sz, result); |
|
25 |
+ } |
|
26 |
+ |
|
27 |
+}; |
|
28 |
+static pwd system_pwd (pwd::delegate (new impl)); |
|
29 |
+} |
|
30 |
+ |
|
31 |
+pwd pwd::system() |
|
32 |
+{ |
|
33 |
+ return system_pwd; |
|
34 |
+} |
|
35 |
+ |
0 | 36 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,49 @@ |
1 |
+/* Copyright (C) CJ Affiliate |
|
2 |
+ * |
|
3 |
+ * You may use, distribute and modify this code under the |
|
4 |
+ * terms of the GNU General Public License version 2 or |
|
5 |
+ * later. |
|
6 |
+ * |
|
7 |
+ * You should have received a copy of the license with this |
|
8 |
+ * file. If not, you will find a copy in the "LICENSE" file |
|
9 |
+ * at https://github.com/cjdev/dual-control. |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+#ifndef _SYS_PWD_H |
|
13 |
+#define _SYS_PWD_H |
|
14 |
+ |
|
15 |
+#include <memory> |
|
16 |
+#include <pwd.h> |
|
17 |
+ |
|
18 |
+class pwd_ifc |
|
19 |
+{ |
|
20 |
+public: |
|
21 |
+ virtual int getpwnam_r (const char *user_name, passwd *out, char *buffer, |
|
22 |
+ size_t buffer_sz, passwd **result) |
|
23 |
+ { |
|
24 |
+ *result = 0; |
|
25 |
+ return 0; |
|
26 |
+ }; |
|
27 |
+}; |
|
28 |
+ |
|
29 |
+class pwd : public pwd_ifc |
|
30 |
+{ |
|
31 |
+public: |
|
32 |
+ typedef std::shared_ptr<pwd_ifc> delegate; |
|
33 |
+ |
|
34 |
+private: |
|
35 |
+ delegate delegate_; |
|
36 |
+ |
|
37 |
+public: |
|
38 |
+ pwd (const delegate delegate) : delegate_ (delegate) {} |
|
39 |
+ pwd() : delegate_ (delegate (new pwd_ifc)) {} |
|
40 |
+ int getpwnam_r (const char *user_name, passwd *out, char *buffer, |
|
41 |
+ size_t buffer_sz, passwd **result) |
|
42 |
+ { |
|
43 |
+ return delegate_-> getpwnam_r (user_name, out, buffer, buffer_sz, result); |
|
44 |
+ } |
|
45 |
+ static pwd system(); |
|
46 |
+}; |
|
47 |
+ |
|
48 |
+#endif |
|
49 |
+ |
0 | 50 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,32 @@ |
1 |
+/* Copyright (C) CJ Affiliate |
|
2 |
+ * |
|
3 |
+ * You may use, distribute and modify this code under the |
|
4 |
+ * terms of the GNU General Public License version 2 or |
|
5 |
+ * later. |
|
6 |
+ * |
|
7 |
+ * You should have received a copy of the license with this |
|
8 |
+ * file. If not, you will find a copy in the "LICENSE" file |
|
9 |
+ * at https://github.com/cjdev/dual-control. |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+#include "sys_unistd.h" |
|
13 |
+#include <unistd.h> |
|
14 |
+ |
|
15 |
+namespace |
|
16 |
+{ |
|
17 |
+class impl : public unistd_ifc |
|
18 |
+{ |
|
19 |
+public: |
|
20 |
+ long int sysconf (int name) |
|
21 |
+ { |
|
22 |
+ return ::sysconf (name); |
|
23 |
+ } |
|
24 |
+}; |
|
25 |
+static unistd sys_unistd (unistd::delegate (new impl)); |
|
26 |
+} |
|
27 |
+ |
|
28 |
+unistd unistd::system() |
|
29 |
+{ |
|
30 |
+ return sys_unistd; |
|
31 |
+} |
|
32 |
+ |
0 | 33 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,47 @@ |
1 |
+/* Copyright (C) CJ Affiliate |
|
2 |
+ * |
|
3 |
+ * You may use, distribute and modify this code under the |
|
4 |
+ * terms of the GNU General Public License version 2 or |
|
5 |
+ * later. |
|
6 |
+ * |
|
7 |
+ * You should have received a copy of the license with this |
|
8 |
+ * file. If not, you will find a copy in the "LICENSE" file |
|
9 |
+ * at https://github.com/cjdev/dual-control. |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+#ifndef _SYS_UNISTD_H_ |
|
13 |
+#define _SYS_UNISTD_H_ |
|
14 |
+ |
|
15 |
+#include <memory> |
|
16 |
+ |
|
17 |
+#include <unistd.h> |
|
18 |
+ |
|
19 |
+class unistd_ifc |
|
20 |
+{ |
|
21 |
+public: |
|
22 |
+ virtual long int sysconf (int name) |
|
23 |
+ { |
|
24 |
+ return -1; |
|
25 |
+ } |
|
26 |
+}; |
|
27 |
+ |
|
28 |
+class unistd : public unistd_ifc |
|
29 |
+{ |
|
30 |
+public: |
|
31 |
+ typedef std::shared_ptr<unistd_ifc> delegate; |
|
32 |
+ |
|
33 |
+private: |
|
34 |
+ delegate delegate_; |
|
35 |
+ |
|
36 |
+public: |
|
37 |
+ unistd (delegate delegate): delegate_ (delegate) {} |
|
38 |
+ unistd() : delegate_ (delegate (new unistd_ifc)) {} |
|
39 |
+ long int sysconf (int name) |
|
40 |
+ { |
|
41 |
+ return delegate_->sysconf (name); |
|
42 |
+ } |
|
43 |
+ static unistd system(); |
|
44 |
+}; |
|
45 |
+ |
|
46 |
+#endif |
|
47 |
+ |
... | ... |
@@ -11,25 +11,44 @@ |
11 | 11 |
|
12 | 12 |
#include <memory> |
13 | 13 |
#include <vector> |
14 |
-#include <string> |
|
15 |
-#include <pwd.h> |
|
16 |
-#include <unistd.h> |
|
17 |
-#include <iostream> |
|
18 | 14 |
|
19 | 15 |
#include "user.h" |
20 |
-#include "test_support.h" |
|
16 |
+#include "sys_unistd.h" |
|
17 |
+#include "sys_pwd.h" |
|
21 | 18 |
|
22 |
-user::user (struct passwd *sys_info) : info (sys_info) |
|
19 |
+namespace |
|
23 | 20 |
{ |
21 |
+class directory_impl : public directory_ifc |
|
22 |
+{ |
|
23 |
+private: |
|
24 |
+ unistd unistd_; |
|
25 |
+ pwd pwd_; |
|
26 |
+public: |
|
27 |
+ directory_impl (unistd &unistd, pwd &pwd) : unistd_ (unistd), pwd_ (pwd) {} |
|
28 |
+ std::vector<user> find_user (const std::string &user_name) |
|
29 |
+ { |
|
30 |
+ std::vector<char> buffer (unistd_.sysconf (_SC_GETPW_R_SIZE_MAX)); |
|
31 |
+ passwd sys_passwd; |
|
32 |
+ passwd *found_passwd (0); |
|
33 |
+ int result = pwd_.getpwnam_r (user_name.c_str(), &sys_passwd, |
|
34 |
+ buffer.data(), buffer.size(), &found_passwd); |
|
35 |
+ std::vector<user> return_value; |
|
36 |
+ |
|
37 |
+ if (!result && found_passwd) { |
|
38 |
+ return_value.push_back (user()); |
|
39 |
+ } |
|
40 |
+ |
|
41 |
+ return return_value; |
|
42 |
+ } |
|
43 |
+}; |
|
24 | 44 |
} |
25 | 45 |
|
26 |
-std::string user::home_directory() |
|
46 |
+directory directory::create (unistd &unistd, pwd &pwd) |
|
27 | 47 |
{ |
28 |
- return info->pw_dir; |
|
48 |
+ return directory (delegate (new directory_impl (unistd, pwd))); |
|
29 | 49 |
} |
30 | 50 |
|
31 |
-// concrete user implementation |
|
32 |
- |
|
51 |
+/* |
|
33 | 52 |
class concrete_user : public user |
34 | 53 |
{ |
35 | 54 |
private: |
... | ... |
@@ -65,4 +84,5 @@ const std::shared_ptr<user> create_user (const std::string &user_name) |
65 | 84 |
|
66 | 85 |
return rval; |
67 | 86 |
} |
87 |
+*/ |
|
68 | 88 |
|
... | ... |
@@ -14,7 +14,9 @@ |
14 | 14 |
#include <vector> |
15 | 15 |
#include <string> |
16 | 16 |
#include <memory> |
17 |
-#include <pwd.h> |
|
17 |
+ |
|
18 |
+#include "sys_unistd.h" |
|
19 |
+#include "sys_pwd.h" |
|
18 | 20 |
|
19 | 21 |
class user_ifc |
20 | 22 |
{ |
... | ... |
@@ -43,19 +45,20 @@ public: |
43 | 45 |
|
44 | 46 |
class directory : public directory_ifc |
45 | 47 |
{ |
48 |
+public: |
|
49 |
+ typedef std::shared_ptr<directory_ifc> delegate; |
|
46 | 50 |
private: |
47 |
- std::shared_ptr<directory_ifc> delegate_; |
|
51 |
+ delegate delegate_; |
|
48 | 52 |
public: |
49 |
- directory (std::shared_ptr<directory_ifc> delegate) : delegate_ |
|
53 |
+ directory (delegate delegate) : delegate_ |
|
50 | 54 |
(delegate) {} |
51 |
- directory() : directory (std::shared_ptr<directory_ifc> |
|
52 |
- (new directory_ifc)) {} |
|
55 |
+ directory() : directory (delegate (new directory_ifc)) {} |
|
53 | 56 |
std::vector<user> find_user (const std::string &user_name) |
54 | 57 |
{ |
55 | 58 |
return delegate_->find_user (user_name); |
56 | 59 |
} |
57 | 60 |
|
58 |
- static directory create(); |
|
61 |
+ static directory create (unistd &unistd, pwd &pwd); |
|
59 | 62 |
}; |
60 | 63 |
|
61 | 64 |
#endif |
... | ... |
@@ -9,87 +9,162 @@ |
9 | 9 |
* at https://github.com/cjdev/dual-control. |
10 | 10 |
*/ |
11 | 11 |
|
12 |
-#include <memory> |
|
13 |
-#include <iostream> |
|
14 | 12 |
#include "user.h" |
15 | 13 |
#include "test_util.h" |
14 |
+#include "sys_pwd.h" |
|
15 |
+#include "sys_unistd.h" |
|
16 | 16 |
|
17 |
-bool gets_home_directory() |
|
17 |
+class fake_pwd : public pwd_ifc |
|
18 |
+{ |
|
19 |
+private: |
|
20 |
+ std::string expected_user_name_; |
|
21 |
+public: |
|
22 |
+ fake_pwd (const std::string expected_user_name) : expected_user_name_ |
|
23 |
+ (expected_user_name) {} |
|
24 |
+ int getpwnam_r (const char *user_name, passwd *out, char *buffer, |
|
25 |
+ size_t buffer_sz, passwd **result) |
|
26 |
+ { |
|
27 |
+ if (expected_user_name_ == user_name) { |
|
28 |
+ *result = out; |
|
29 |
+ } else { |
|
30 |
+ *result = 0; |
|
31 |
+ } |
|
32 |
+ |
|
33 |
+ return 0; |
|
34 |
+ } |
|
35 |
+}; |
|
36 |
+ |
|
37 |
+class match_buffer_pwd : public pwd_ifc |
|
38 |
+{ |
|
39 |
+private: |
|
40 |
+ long int expected_buffer_sz_; |
|
41 |
+public: |
|
42 |
+ match_buffer_pwd (long int buffer_sz) : expected_buffer_sz_ (buffer_sz) {} |
|
43 |
+ int getpwnam_r (const char *user_name, passwd *out, char *buffer, |
|
44 |
+ size_t buffer_sz, passwd **result) |
|
45 |
+ { |
|
46 |
+ |
|
47 |
+ if (expected_buffer_sz_ == buffer_sz && buffer != 0) { |
|
48 |
+ *result = out; |
|
49 |
+ } else { |
|
50 |
+ *result = 0; |
|
51 |
+ } |
|
52 |
+ |
|
53 |
+ return 0; |
|
54 |
+ } |
|
55 |
+}; |
|
56 |
+ |
|
57 |
+class stub_pwnam_err_pwd : public pwd_ifc |
|
58 |
+{ |
|
59 |
+public: |
|
60 |
+ int getpwnam_r (const char *user_name, passwd *out, char *buffer, |
|
61 |
+ size_t buffer_sz, passwd **result) |
|
62 |
+ { |
|
63 |
+ *result = out; |
|
64 |
+ return 3; |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+}; |
|
68 |
+ |
|
69 |
+class fake_unistd : public unistd_ifc |
|
70 |
+{ |
|
71 |
+private: |
|
72 |
+ int expected_name_; |
|
73 |
+ long int return_value_; |
|
74 |
+public: |
|
75 |
+ fake_unistd (int expected_name, long int return_value = 0) |
|
76 |
+ : expected_name_ (expected_name), |
|
77 |
+ return_value_ (return_value) {} |
|
78 |
+ long int sysconf (int name) |
|
79 |
+ { |
|
80 |
+ if (name == expected_name_) { |
|
81 |
+ return return_value_; |
|
82 |
+ } |
|
83 |
+ |
|
84 |
+ return -1; |
|
85 |
+ } |
|
86 |
+}; |
|
87 |
+ |
|
88 |
+int find_user_happy() |
|
18 | 89 |
{ |
19 | 90 |
//given |
20 |
- const char *expected_home_directory = "home/msmith"; |
|
21 |
- struct passwd test_passwd; |
|
22 |
- test_passwd.pw_dir = const_cast<char *> (expected_home_directory); |
|
23 |
- user test_user (&test_passwd); |
|
91 |
+ std::string user_name ("user"); |
|
92 |
+ pwd test_pwd (pwd::delegate (new fake_pwd (user_name))); |
|
93 |
+ unistd test_unistd (unistd::delegate (new fake_unistd ( |
|
94 |
+ _SC_GETPW_R_SIZE_MAX))); |
|
95 |
+ directory directory (directory::create (test_unistd, test_pwd)); |
|
24 | 96 |
|
25 | 97 |
//when |
26 |
- std::string actual_home_directory = test_user.home_directory(); |
|
98 |
+ std::vector<user> results = directory.find_user (user_name); |
|
27 | 99 |
|
28 | 100 |
//then |
29 |
- check (expected_home_directory == actual_home_directory, |
|
30 |
- "directories do not match"); |
|
31 |
- return expected_home_directory == actual_home_directory; |
|
101 |
+ check (!results.empty(), "user should have been found"); |
|
102 |
+ succeed(); |
|
32 | 103 |
} |
33 | 104 |
|
34 |
-std::shared_ptr<struct passwd> fake_passwd; |
|
35 |
-int fake_getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, |
|
36 |
- size_t bufsize, struct passwd **result) |
|
105 |
+int user_not_found() |
|
37 | 106 |
{ |
38 |
- if (fake_passwd) { |
|
39 |
- *pwd = *fake_passwd; |
|
40 |
- *result = pwd; |
|
41 |
- return 0; |
|
42 |
- } |
|
107 |
+ //given |
|
108 |
+ pwd test_pwd (pwd::delegate (new fake_pwd ("user"))); |
|
109 |
+ unistd test_unistd (unistd::delegate (new fake_unistd ( |
|
110 |
+ _SC_GETPW_R_SIZE_MAX))); |
|
111 |
+ directory directory (directory::create (test_unistd, test_pwd)); |
|
112 |
+ |
|
113 |
+ //when |
|
114 |
+ std::vector<user> results = directory.find_user ("not_user"); |
|
115 |
+ |
|
116 |
+ //then |
|
117 |
+ check (results.empty(), "user should not have been found"); |
|
118 |
+ succeed(); |
|
43 | 119 |
|
44 |
- return -1; |
|
45 | 120 |
} |
46 | 121 |
|
47 |
-bool create_user_succeeds() |
|
122 |
+int find_user_passes_buffer_and_size() |
|
48 | 123 |
{ |
49 |
- // given |
|
50 |
- std::string username ("msmith"); |
|
51 |
- std::string home_directory ("this is my home"); |
|
52 |
- fake_passwd.reset (new struct passwd); |
|
53 |
- fake_passwd->pw_dir = const_cast<char *> (home_directory.c_str()); |
|
124 |
+ //given |
|
125 |
+ long int buffer_sz = 5976; |
|
126 |
+ unistd test_unistd (unistd::delegate (new fake_unistd (_SC_GETPW_R_SIZE_MAX, |
|
127 |
+ buffer_sz))); |
|
128 |
+ pwd match_pwd (pwd::delegate (new match_buffer_pwd (buffer_sz))); |
|
129 |
+ directory directory (directory::create (test_unistd, match_pwd)); |
|
54 | 130 |
|
55 |
- // when |
|
56 |
- std::shared_ptr<user> user (create_user (username)); |
|
131 |
+ //when |
|
132 |
+ std::vector<user> results = directory.find_user ("does_not_matter"); |
|
57 | 133 |
|
58 | 134 |
// then |
59 |
- check (user, "user should be returned"); |
|
60 |
- check (user->home_directory() == home_directory, |
|
61 |
- "home directory does not match"); |
|
62 |
- |
|
135 |
+ check (!results.empty(), "match failed"); |
|
63 | 136 |
succeed(); |
64 |
- |
|
65 | 137 |
} |
66 | 138 |
|
67 |
-bool create_user_nonexistent() |
|
139 |
+int find_user_fails_on_pwnam_r_error_and_result_ok() |
|
68 | 140 |
{ |
69 |
- // given |
|
70 |
- std::string username ("msmith"); |
|
141 |
+ //given |
|
142 |
+ unistd test_unistd (unistd::delegate (new fake_unistd ( |
|
143 |
+ _SC_GETPW_R_SIZE_MAX))); |
|
144 |
+ pwd stub_pwd (pwd::delegate (new stub_pwnam_err_pwd)); |
|
145 |
+ directory directory (directory::create (test_unistd, stub_pwd)); |
|
71 | 146 |
|
72 |
- // when |
|
73 |
- std::shared_ptr<user> user (create_user (username)); |
|
147 |
+ //when |
|
148 |
+ std::vector<user> results = directory.find_user ("does_not_matter"); |
|
74 | 149 |
|
75 | 150 |
// then |
76 |
- check (!user, "no user should be returned"); |
|
77 |
- |
|
151 |
+ check (results.empty(), "did not check return"); |
|
78 | 152 |
succeed(); |
79 | 153 |
} |
80 | 154 |
|
81 | 155 |
RESET_VARS_START |
82 |
-fake_passwd.reset ((struct passwd *)0); |
|
83 | 156 |
RESET_VARS_END |
84 | 157 |
|
85 | 158 |
int run_tests() |
86 | 159 |
{ |
87 |
- test (gets_home_directory); |
|
88 |
- test (create_user_succeeds); |
|
89 |
- test (create_user_nonexistent); |
|
160 |
+ test (find_user_happy); |
|
161 |
+ test (user_not_found); |
|
162 |
+ test (find_user_passes_buffer_and_size); |
|
163 |
+ test (find_user_fails_on_pwnam_r_error_and_result_ok); |
|
90 | 164 |
succeed(); |
91 | 165 |
} |
92 |
-int main (int argc, char *argv[]) |
|
166 |
+ |
|
167 |
+int main (int argc, char **argv) |
|
93 | 168 |
{ |
94 | 169 |
return !run_tests(); |
95 | 170 |
} |