1 /* check-sources:disable-copyright-check */
2 /* unit test the sproxyd protocol backend */
3 #include <sys/types.h>
4 #include <limits.h>
5 #include <stdio.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <errno.h>
12 #include <check.h>
13 #include <droplet.h>
14
15 #include "toyctl.h"
16 #include "testutils.h"
17 #include "utest_main.h"
18
19 static struct server_state* state = NULL;
20 static dpl_dict_t* profile = NULL;
21 static dpl_ctx_t* ctx = NULL;
22
setup(void)23 static void setup(void)
24 {
25 int r;
26
27 unsetenv("DPLDIR");
28 unsetenv("DPLPROFILE");
29 dpl_init();
30
31 r = toyserver_start(NULL, &state);
32 dpl_assert_int_eq(r, 0);
33
34 profile = dpl_dict_new(13);
35 dpl_assert_ptr_not_null(profile);
36 dpl_assert_int_eq(
37 DPL_SUCCESS, dpl_dict_add(profile, "host", toyserver_addrlist(state), 0));
38 dpl_assert_int_eq(DPL_SUCCESS,
39 dpl_dict_add(profile, "backend", "sproxyd", 0));
40 dpl_assert_int_eq(DPL_SUCCESS,
41 dpl_dict_add(profile, "base_path", "/proxy/chord", 0));
42 dpl_assert_int_eq(DPL_SUCCESS,
43 dpl_dict_add(profile, "droplet_dir", "/never/seen", 0));
44 dpl_assert_int_eq(DPL_SUCCESS,
45 dpl_dict_add(profile, "profile_name", "viral", 0));
46 /* need this to disable the event log, otherwise the droplet_dir needs to
47 * exist */
48 dpl_assert_int_eq(DPL_SUCCESS, dpl_dict_add(profile, "pricing_dir", "", 0));
49 }
50
teardown(void)51 static void teardown(void)
52 {
53 if (ctx) dpl_ctx_free(ctx);
54
55 dpl_dict_free(profile);
56 toyserver_stop(state);
57 }
58
START_TEST(get_set_test)59 START_TEST(get_set_test)
60 {
61 dpl_status_t s;
62 char* expected_uri;
63 int r;
64 char id[41];
65 static const char data[]
66 = "Carles wolf yr Austin, chambray twee lo-fi iPhone brunch Neutra"
67 "slow-carb. Viral +1 kitsch fashion axe wolf. Selvage flexitarian"
68 "ugh banjo Godard, jean shorts occupy Marfa fingerstache literally"
69 "whatever keffiyeh put a bird on it biodiesel brunch. Forage plaid"
70 "wolf kitsch Etsy. Literally ugh Carles, Intelligentsia sartorial";
71
72 /* create a context with all defaults */
73 ctx = dpl_ctx_new_from_dict(profile);
74 dpl_assert_ptr_not_null(ctx);
75
76 s = dpl_gen_random_key(ctx, DPL_STORAGE_CLASS_STANDARD, /*custom*/ NULL, id,
77 sizeof(id));
78 dpl_assert_int_eq(DPL_SUCCESS, s);
79
80 s = dpl_put_id(ctx, "foobucket", id,
81 /*options*/ NULL, DPL_FTYPE_REG,
82 /*condition*/ NULL,
83 /*range*/ NULL,
84 /*metadata*/ NULL,
85 /*sysmd*/ NULL, data, sizeof(data) - 1);
86 dpl_assert_int_eq(DPL_SUCCESS, s);
87
88 dpl_assert_str_eq(state->request.host, toyserver_addrlist(state));
89 expected_uri = strconcat("/proxy/chord/", id, (char*)NULL);
90 dpl_assert_str_eq(state->request.uri, expected_uri);
91 dpl_assert_str_eq(state->request.body, data);
92 dpl_assert_int_eq(state->reply.status, 200);
93
94 // s = dpl_get_id(ctx, "foobucket", id, /*options*/NULL, DPL_FTYPE_REG,
95 // /*condition*/NULL, /*range*/NULL, char **data_bufp, unsigned int
96 // *data_lenp, dpl_dict_t **metadatap, dpl_sysmd_t *sysmdp);
97 // dpl_assert_int_eq(DPL_SUCCESS, s);
98
99 free(expected_uri);
100 }
101 END_TEST
102
send_authenticated_request(const char * username,const char * password,struct request * reqp)103 static dpl_status_t send_authenticated_request(const char* username,
104 const char* password,
105 struct request* reqp)
106 {
107 dpl_status_t s;
108 dpl_dict_t* prof2;
109 char id[41];
110 static const char data[]
111 = "Carles wolf yr Austin, chambray twee lo-fi iPhone brunch Neutra"
112 "slow-carb. Viral";
113
114 prof2 = dpl_dict_dup(profile);
115 if (username)
116 dpl_assert_int_eq(DPL_SUCCESS,
117 dpl_dict_add(prof2, "access_key", username, 0));
118 if (password)
119 dpl_assert_int_eq(DPL_SUCCESS,
120 dpl_dict_add(prof2, "secret_key", password, 0));
121
122 /* create an unauthenticated context */
123 ctx = dpl_ctx_new_from_dict(prof2);
124 dpl_assert_ptr_not_null(ctx);
125 dpl_dict_free(prof2);
126
127 s = dpl_gen_random_key(ctx, DPL_STORAGE_CLASS_STANDARD, /*custom*/ NULL, id,
128 sizeof(id));
129 dpl_assert_int_eq(DPL_SUCCESS, s);
130
131 s = dpl_put_id(ctx, "foobucket", id,
132 /*options*/ NULL, DPL_FTYPE_REG,
133 /*condition*/ NULL,
134 /*range*/ NULL,
135 /*metadata*/ NULL,
136 /*sysmd*/ NULL, data, sizeof(data) - 1);
137 if (reqp) *reqp = state->request; /* sample before disconnection */
138
139 dpl_ctx_free(ctx);
140 ctx = NULL;
141
142 return s;
143 }
144
START_TEST(basic_auth_test)145 START_TEST(basic_auth_test)
146 {
147 #define TESTCASE(u, p, ehasa, eu, ep, es) \
148 { \
149 dpl_status_t s; \
150 struct request req; \
151 memset(&req, 0, sizeof(req)); \
152 s = send_authenticated_request(u, p, &req); \
153 dpl_assert_int_eq(req.has_authorization, ehasa); \
154 dpl_assert_str_eq(req.username, eu); \
155 dpl_assert_str_eq(req.password, ep); \
156 dpl_assert_int_eq(s, es); \
157 }
158
159
160 /* By default, server notices authentication but doesn't care */
161
162 /* unauthenticated request succeeds */
163 TESTCASE(NULL, NULL,
164 /*has_authorization*/ 0, "", "", DPL_SUCCESS);
165
166 /* authenticated request with random username & password succeeds */
167 TESTCASE("brooklyn", "sriracha",
168 /*has_authorization*/ 1, "brooklyn", "sriracha", DPL_SUCCESS);
169
170 /* Server will now refuse unauthenticated requests
171 * and requests with the wrong username or password. */
172 state->config.require_basic_auth = 1;
173
174 /* unauthenticated request fails */
175 TESTCASE(NULL, NULL,
176 /*has_authorization*/ 0, "", "", DPL_FAILURE);
177
178 /* authenticated request with bad username fails */
179 TESTCASE("not" TOY_USERNAME, TOY_PASSWORD,
180 /*has_authorization*/ 1, "not" TOY_USERNAME, TOY_PASSWORD,
181 DPL_EPERM);
182
183 /* authenticated request with bad password fails */
184 TESTCASE(TOY_USERNAME, "not" TOY_PASSWORD,
185 /*has_authorization*/ 1, TOY_USERNAME, "not" TOY_PASSWORD,
186 DPL_EPERM);
187
188 /* authenticated request with good username and password succeeds */
189 TESTCASE(TOY_USERNAME, TOY_PASSWORD,
190 /*has_authorization*/ 1, TOY_USERNAME, TOY_PASSWORD, DPL_SUCCESS);
191 #undef TESTCASE
192 }
193 END_TEST
194
sproxyd_suite()195 Suite* sproxyd_suite()
196 {
197 Suite* s = suite_create("sproxyd");
198 TCase* t = tcase_create("base");
199 tcase_add_checked_fixture(t, setup, teardown);
200 tcase_add_test(t, get_set_test);
201 tcase_add_test(t, basic_auth_test);
202 suite_add_tcase(s, t);
203 return s;
204 }
205