napa-baselibs / tests / RepoClient / RepoClient.c @ 507372bb
History | View | Annotate | Download (7.5 KB)
1 |
#include <stdio.h> |
---|---|
2 |
#include <stdlib.h> |
3 |
#include <string.h> |
4 |
|
5 |
#include <confuse.h> |
6 |
#include <event2/event.h> |
7 |
#include <event2/buffer.h> |
8 |
#include <event2/http.h> |
9 |
#include <event2/http_struct.h> |
10 |
|
11 |
#include <napa.h> |
12 |
#include <napa_log.h> |
13 |
#include <repoclient.h> |
14 |
#include <ml.h> |
15 |
|
16 |
#define PUBLISH "Publish" |
17 |
#define LISTNAMES "ListMeasurementNames" |
18 |
#define GETPEERS "GetPeers" |
19 |
#define COUNTPEERS "CountPeers" |
20 |
#define GETMEASUREMENTS "GetMeasurementRecords" |
21 |
|
22 |
struct event_base *eventbase;
|
23 |
|
24 |
/* Configuration file parsing instructions. see repoclient_test.cfg for an example */
|
25 |
cfg_opt_t opts_listMeasurementNames[] = { |
26 |
CFG_INT("maxresults", 0, CFGF_NONE), |
27 |
CFG_STR("channel", NULL, CFGF_NONE), |
28 |
CFG_END() |
29 |
}; |
30 |
cfg_opt_t opts_publish[] = { |
31 |
CFG_STR("originator", "", CFGF_NONE), |
32 |
CFG_STR("targetA", "?", CFGF_NONE), |
33 |
CFG_STR("targetB", NULL, CFGF_NONE), |
34 |
CFG_STR("name", "", CFGF_NONE), |
35 |
CFG_FLOAT("value", 0.0, CFGF_NONE), |
36 |
CFG_STR("string_value", NULL, CFGF_NONE), |
37 |
CFG_STR("timestamp", "now", CFGF_NONE), |
38 |
CFG_STR("channel", NULL, CFGF_NONE), |
39 |
CFG_END() |
40 |
}; |
41 |
cfg_opt_t opts_constraint[] = { |
42 |
CFG_STR("name", "", CFGF_NONE), |
43 |
CFG_STR("string_value", "", CFGF_NONE), |
44 |
CFG_FLOAT("min", 0.0, CFGF_NONE), |
45 |
CFG_FLOAT("max", 0.0, CFGF_NONE), |
46 |
CFG_END() |
47 |
}; |
48 |
cfg_opt_t opts_ranking[] = { |
49 |
CFG_STR("name", "", CFGF_NONE), |
50 |
CFG_FLOAT("weight", 1.0, CFGF_NONE), |
51 |
CFG_END() |
52 |
}; |
53 |
cfg_opt_t opts_getpeers[] = { |
54 |
CFG_INT("maxresults", 0, CFGF_NONE), |
55 |
CFG_SEC("constraint", opts_constraint, CFGF_MULTI),
|
56 |
CFG_SEC("ranking", opts_ranking, CFGF_MULTI),
|
57 |
CFG_STR("channel", NULL, CFGF_NONE), |
58 |
CFG_END() |
59 |
|
60 |
}; |
61 |
cfg_opt_t opts_getmeasurements[] = { |
62 |
CFG_INT("maxresults", 0, CFGF_NONE), |
63 |
CFG_STR("originator", NULL, CFGF_NONE), |
64 |
CFG_STR("targetA", NULL, CFGF_NONE), |
65 |
CFG_STR("targetB", NULL, CFGF_NONE), |
66 |
CFG_STR("name", NULL, CFGF_NONE), |
67 |
CFG_STR("channel", NULL, CFGF_NONE), |
68 |
CFG_END() |
69 |
}; |
70 |
cfg_opt_t opts_test[] = { |
71 |
CFG_SEC(LISTNAMES, opts_listMeasurementNames, CFGF_MULTI), |
72 |
CFG_SEC(PUBLISH, opts_publish, CFGF_MULTI), |
73 |
CFG_SEC(GETPEERS, opts_getpeers, CFGF_MULTI), |
74 |
CFG_SEC(GETMEASUREMENTS, opts_getmeasurements, CFGF_MULTI), |
75 |
CFG_END() |
76 |
}; |
77 |
cfg_opt_t opts_repospec[] = { |
78 |
CFG_STR("server", "192.168.35.203:9832", CFGF_NONE), |
79 |
CFG_END() |
80 |
}; |
81 |
cfg_opt_t repotest_opts[] = { |
82 |
CFG_SEC("repository", opts_repospec, CFGF_NONE),
|
83 |
CFG_SEC("test", opts_test, CFGF_MULTI),
|
84 |
CFG_END() |
85 |
}; |
86 |
|
87 |
int tests_done = 0; |
88 |
struct timeval parse_timestamp(const char *ts); |
89 |
|
90 |
/** Helper to print a string list */
|
91 |
const char *print_list(char **list, int n, bool should_free) { |
92 |
static char buffer[4096]; |
93 |
strcpy(buffer, "[ ");
|
94 |
int i;
|
95 |
for (i = 0; i != n; i++) { |
96 |
if (i) strcat(buffer, ", "); |
97 |
strcat(buffer, list[i]); |
98 |
if (should_free) free(list[i]);
|
99 |
} |
100 |
strcat(buffer, " ]");
|
101 |
if (should_free) free(list);
|
102 |
return buffer;
|
103 |
} |
104 |
|
105 |
void getMeasurements_callback(HANDLE client, HANDLE id, void *cbarg, MeasurementRecord *result, int n) { |
106 |
tests_done++; |
107 |
info("GetMeasurements id %p done, size: %d", id, n);
|
108 |
if (!n) return; |
109 |
int i;
|
110 |
for (i = 0; i != n; i++) { |
111 |
debug("i: %d, channel %p", i, result[i].channel);
|
112 |
info("Record %d: %s", i+1, measurementrecord2str(result[i])); |
113 |
} |
114 |
free(result); |
115 |
} |
116 |
|
117 |
void listMeasurementNames_callback(HANDLE client, HANDLE id, void *cbarg, char **result, int n) { |
118 |
tests_done++; |
119 |
info("ListMeasurementIds id %p done, result: %s", id, print_list(result, n, 1)); |
120 |
} |
121 |
|
122 |
void getPeers_callback(HANDLE client, HANDLE id, void *cbarg, char **result, int n) { |
123 |
tests_done++; |
124 |
info("GetPeers id %p done, result: %s", id, print_list(result, n, 1)); |
125 |
} |
126 |
|
127 |
void publish_callback(HANDLE client, HANDLE id, void *cbarg, int result) { |
128 |
info("Publish done(id:%p), result %d", id, result);
|
129 |
tests_done++; |
130 |
} |
131 |
|
132 |
int ntests;
|
133 |
cfg_t *cfg; |
134 |
HANDLE repoclient; |
135 |
char *configfile;
|
136 |
|
137 |
void do_tests(HANDLE h, void *arg); |
138 |
|
139 |
int main(int argc, char *argv[]) { |
140 |
/* Check for usage (arguments) */
|
141 |
if (argc < 2) { |
142 |
fprintf(stderr, "Usage: %s repotest.cfg\n", argv[0]); |
143 |
exit(1);
|
144 |
} |
145 |
/* Initialize libevent and logging */
|
146 |
eventbase = event_base_new(); |
147 |
napaInitLog(LOG_DEBUG, NULL, NULL); |
148 |
repInit("");
|
149 |
|
150 |
/* Parse config file and init repoclient with the "repository" cfg section */
|
151 |
configfile = argv[1];
|
152 |
cfg = cfg_init(repotest_opts, CFGF_NONE); |
153 |
if(cfg_parse(cfg, configfile) == CFG_PARSE_ERROR)
|
154 |
fatal("Unable to parse config file %s", configfile);
|
155 |
|
156 |
repoclient = repOpen(cfg_getstr(cfg_getsec(cfg, "repository"), "server"),3); |
157 |
if (repoclient == NULL) fatal("Unable to initialize repoclient"); |
158 |
|
159 |
ntests = cfg_size(cfg, "test");
|
160 |
if (!ntests) fatal("No tests specified, exiting"); |
161 |
|
162 |
struct timeval t = { 1, 0 }; |
163 |
napaSchedulePeriodic(&t, 1.0/5.0, do_tests, NULL); |
164 |
do_tests(NULL, NULL); |
165 |
|
166 |
repClose(repoclient); |
167 |
|
168 |
cfg_free(cfg); |
169 |
event_base_free(eventbase); |
170 |
} |
171 |
|
172 |
void do_tests(HANDLE h, void *arg) { |
173 |
int i;
|
174 |
for (i = 0; i != ntests; i++) { |
175 |
cfg_t *test = cfg_getnsec(cfg, "test", i);
|
176 |
|
177 |
if ((cfg_size(test, PUBLISH) + cfg_size(test,LISTNAMES) + cfg_size(test,GETPEERS) +
|
178 |
cfg_size(test,GETMEASUREMENTS)) != 1)
|
179 |
fatal("A test clause must contain exactly one action in %s", configfile);
|
180 |
|
181 |
info("Performing test %d/%d", i+1, ntests); |
182 |
cfg_t *action; |
183 |
|
184 |
if ((action = cfg_getsec(test, PUBLISH)) != NULL) { |
185 |
char AsocketID[SOCKETID_SIZE] = "Unknown"; |
186 |
char BsocketID[SOCKETID_SIZE] = "Unknown"; |
187 |
MeasurementRecord r; |
188 |
r.originator = cfg_getstr(action, "originator");
|
189 |
r.targetA = cfg_getstr(action, "targetA");
|
190 |
r.targetB = cfg_getstr(action, "targetB");
|
191 |
r.published_name = cfg_getstr(action, "name");
|
192 |
r.value = cfg_getfloat(action, "value");
|
193 |
r.string_value = cfg_getstr(action, "string_value");
|
194 |
r.channel = cfg_getstr(action, "channel");
|
195 |
r.timestamp = parse_timestamp(cfg_getstr(action, "timestamp"));
|
196 |
repPublish(repoclient, publish_callback, NULL, &r);
|
197 |
} |
198 |
if ((action = cfg_getsec(test, LISTNAMES)) != NULL) { |
199 |
repListMeasurementNames(repoclient, listMeasurementNames_callback, NULL,
|
200 |
cfg_getint(action, "maxresults"), cfg_getstr(action, "channel")); |
201 |
continue;
|
202 |
} |
203 |
if ((action = cfg_getsec(test, GETMEASUREMENTS)) != NULL) { |
204 |
repGetMeasurements(repoclient, getMeasurements_callback, NULL,
|
205 |
cfg_getint(action, "maxresults"),
|
206 |
cfg_getstr(action, "originator"), cfg_getstr(action, "targetA"), |
207 |
cfg_getstr(action, "targetB"), cfg_getstr(action, "name"), |
208 |
cfg_getstr(action, "channel"));
|
209 |
continue;
|
210 |
} |
211 |
if ((action = cfg_getsec(test, GETPEERS)) != NULL) { |
212 |
int ncons = cfg_size(action, "constraint"); |
213 |
int nranks = cfg_size(action, "ranking"); |
214 |
Constraint *cons = NULL;
|
215 |
Ranking *ranks = NULL;
|
216 |
if (ncons) cons = calloc(ncons, sizeof(Constraint)); |
217 |
if (nranks) ranks = calloc(nranks, sizeof(Ranking)); |
218 |
int j;
|
219 |
for (j = 0; j != ncons; j++) { |
220 |
cfg_t *con = cfg_getnsec(action, "constraint", j);
|
221 |
cons[j].published_name = cfg_getstr(con, "name");
|
222 |
cons[j].maxValue = cfg_getfloat(con, "max");
|
223 |
cons[j].minValue = cfg_getfloat(con, "min");
|
224 |
} |
225 |
for (j = 0; j != nranks; j++) { |
226 |
cfg_t *con = cfg_getnsec(action, "ranking", j);
|
227 |
ranks[j].published_name = cfg_getstr(con, "name");
|
228 |
ranks[j].weight = cfg_getfloat(con, "weight");
|
229 |
} |
230 |
HANDLE h = repGetPeers(repoclient, getPeers_callback, NULL,
|
231 |
cfg_getint(action, "maxresults"),
|
232 |
cons, ncons, ranks, nranks, cfg_getstr(action, "channel"));
|
233 |
continue;
|
234 |
} |
235 |
} |
236 |
|
237 |
int last_done = tests_done - 1; |
238 |
while (tests_done != ntests) {
|
239 |
if (last_done != tests_done) debug("Test %d/%d done", tests_done, ntests); |
240 |
last_done = tests_done; |
241 |
event_base_loop(eventbase, EVLOOP_ONCE); |
242 |
} |
243 |
} |
244 |
|
245 |
struct timeval parse_timestamp(const char *ts) { |
246 |
struct timeval ret;
|
247 |
ret.tv_usec = 0;
|
248 |
|
249 |
if (!strcmp(ts, "now")) { |
250 |
ret.tv_sec = time(NULL);
|
251 |
return ret;
|
252 |
} |
253 |
ret.tv_sec = 0;
|
254 |
return ret;
|
255 |
} |