Asterisk - The Open Source Telephony Project  18.5.0
test_file.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2016, Digium, Inc.
5  *
6  * Kevin Harwell <[email protected]>
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) {
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 
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);
193 }
194 
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
Asterisk main include file. File version handling, generic pbx functions.
String manipulation functions.
#define FOUND
Definition: test_file.c:36
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
Test Framework API.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
static int test_files_destroy(struct ast_test *test, char *dir_name, struct _filenames *filenames)
Definition: test_file.c:49
static int load_module(void)
Definition: test_file.c:189
#define ast_str_alloca(init_len)
Definition: strings.h:800
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define NULL
Definition: resample.c:96
int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
Recursively iterate through files and directories up to max_depth.
Definition: file.c:1231
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define ast_log
Definition: astobj2.c:42
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
Asterisk file paths, configured in asterisk.conf.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
long int ast_random(void)
Definition: main/utils.c:2064
AST_VECTOR(_filenames, struct ast_str *)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
char * mkdtemp(char *template_s)
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
int errno
static void rm_file(struct ast_str *filename)
Definition: test_file.c:40
static int unload_module(void)
Definition: test_file.c:183
#define ast_free(a)
Definition: astmm.h:182
static char * test_files_get_one(struct _filenames *filenames, int num)
Definition: test_file.c:112
Vector container support.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
Definition: test.c:65
AST_TEST_DEFINE(read_dirs_test)
Definition: test_file.c:136
static int test_files_create(struct ast_test *test, char *dir_name, struct _filenames *filenames, int num)
Definition: test_file.c:66
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static int handle_find_file(const char *dir_name, const char *filename, void *obj)
Definition: test_file.c:119
ast_test_result_state
Definition: test.h:200
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:865
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620