Merge "doc/lang/language-criteria.txt: Link to wiki."
[asterisk/asterisk.git] / tests / test_file.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2016, Digium, Inc.
5  *
6  * Kevin Harwell <kharwell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*** MODULEINFO
20         <depend>TEST_FRAMEWORK</depend>
21         <support_level>core</support_level>
22  ***/
23
24
25 #include "asterisk.h"
26 #include <sys/stat.h>
27 #include <stdio.h>
28
29 #include "asterisk/file.h"
30 #include "asterisk/paths.h"
31 #include "asterisk/test.h"
32 #include "asterisk/module.h"
33 #include "asterisk/strings.h"
34 #include "asterisk/vector.h"
35
36 #define FOUND -7
37
38 AST_VECTOR(_filenames, struct ast_str *);
39
40 static void rm_file(struct ast_str *filename)
41 {
42         if (unlink(ast_str_buffer(filename))) {
43                 ast_log(LOG_ERROR, "Unable to remove file: %s\n", ast_str_buffer(filename));
44         }
45
46         ast_free(filename);
47 }
48
49 static int test_files_destroy(struct ast_test *test, char *dir_name,
50                               struct _filenames *filenames)
51 {
52         int res;
53
54         if (filenames) {
55                 AST_VECTOR_CALLBACK_VOID(filenames, rm_file);
56                 AST_VECTOR_FREE(filenames);
57         }
58
59         if ((res = rmdir(dir_name)) < 0) {
60                 ast_test_status_update(test, "Failed to remove directory: %s\n", dir_name);
61         }
62
63         return res;
64 }
65
66 static int test_files_create(struct ast_test *test, char *dir_name,
67                              struct _filenames *filenames, int num)
68 {
69         int i;
70
71         if (!(mkdtemp(dir_name))) {
72                 ast_test_status_update(test, "Failed to create directory: %s\n", dir_name);
73                 return -1;
74         }
75
76
77         AST_VECTOR_INIT(filenames, num);
78
79         /*
80          * Create "num" files under the specified directory
81          */
82         for (i = 0; i < num; ++i) {
83                 int fd;
84                 struct ast_str *filename = ast_str_create(32);
85
86                 if (!filename) {
87                         break;
88                 }
89
90                 ast_str_set(&filename, 0, "%s/XXXXXX", dir_name);
91
92                 fd = mkstemp(ast_str_buffer(filename));
93                 if (fd < 0) {
94                         ast_test_status_update(test, "Failed to create file: %s\n",
95                                                ast_str_buffer(filename));
96                         ast_free(filename);
97                         break;
98                 }
99                 close(fd);
100
101                 AST_VECTOR_APPEND(filenames, filename);
102         }
103
104         if (i != num) {
105                 test_files_destroy(test, dir_name, filenames);
106                 return -1;
107         }
108
109         return 0;
110 }
111
112 static char *test_files_get_one(struct _filenames *filenames, int num)
113 {
114         /* Every file is in a directory and contains a '/' so okay to do this */
115         return strrchr(ast_str_buffer(
116                        AST_VECTOR_GET(filenames, ast_random() % (num - 1))), '/') + 1;
117 }
118
119 static int handle_find_file(const char *dir_name, const char *filename, void *obj)
120 {
121         struct stat statbuf;
122         char *full_path = ast_alloca(strlen(dir_name) + strlen(filename) + 2);
123
124         sprintf(full_path, "%s/%s", dir_name, filename);
125
126         errno = 0;
127         if (stat(full_path, &statbuf)) {
128                 ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n",
129                         full_path, strerror(errno));
130                 return 0;
131         }
132         /* obj contains the name of the file we are looking for */
133         return strcmp(obj, filename) ? 0 : FOUND;
134 }
135
136 AST_TEST_DEFINE(read_dirs_test)
137 {
138         char tmp_dir[] = "/tmp/tmpdir.XXXXXX";
139         struct ast_str *tmp_sub_dir;
140         struct _filenames filenames;
141         enum ast_test_result_state res;
142         const int num_files = 10 + (ast_random() % 10); /* 10-19 random files */
143
144         switch (cmd) {
145         case TEST_INIT:
146                 info->name = "read_dir_test";
147                 info->category = "/main/file/";
148                 info->summary = "Read a directory's content";
149                 info->description = "Iterate over directories looking for a file.";
150                 return AST_TEST_NOT_RUN;
151         case TEST_EXECUTE:
152                 break;
153         }
154
155         /*
156          * We want to test recursively searching into a subdirectory, so
157          * create a top level tmp directory where we will start the search.
158          */
159         if (!(mkdtemp(tmp_dir))) {
160                 ast_test_status_update(test, "Failed to create directory: %s\n", tmp_dir);
161                 return AST_TEST_FAIL;
162         }
163
164         tmp_sub_dir = ast_str_alloca(32);
165         ast_str_set(&tmp_sub_dir, 0, "%s/XXXXXX", tmp_dir);
166
167         if (test_files_create(test, ast_str_buffer(tmp_sub_dir), &filenames, num_files)) {
168                 test_files_destroy(test, tmp_dir, NULL);
169                 return AST_TEST_FAIL;
170         }
171
172         res = ast_file_read_dirs(tmp_dir, handle_find_file, test_files_get_one(
173                  &filenames, num_files), 2) == FOUND ? AST_TEST_PASS : AST_TEST_FAIL;
174
175         if (test_files_destroy(test, ast_str_buffer(tmp_sub_dir), &filenames) ||
176             test_files_destroy(test, tmp_dir, NULL)) {
177                 res = AST_TEST_FAIL;
178         }
179
180         return res;
181 }
182
183 static int unload_module(void)
184 {
185         AST_TEST_UNREGISTER(read_dirs_test);
186         return 0;
187 }
188
189 static int load_module(void)
190 {
191         AST_TEST_REGISTER(read_dirs_test);
192         return AST_MODULE_LOAD_SUCCESS;
193 }
194
195 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "File test module");