root/test/test-file-io.c

Revision 7fc7cc43795e2dc3eca7e924d74101d441bafb67, 7.1 kB (checked in by Hans Petter Jansson <hpj@gong.(none)>, 2 years ago)

Implement GError error reporting in high-level I/O functions.

  • Property mode set to 100644
Line 
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
3 /* test-tcp-io.c - FlowTcpIO test.
4  *
5  * Copyright (C) 2006 Hans Petter Jansson
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * Authors: Hans Petter Jansson <hpj@copyleft.no>
23  */
24
25 #define TEST_UNIT_NAME "FlowFileIO"
26 #define TEST_TIMEOUT_S 180
27
28 /* Test variables; adjustable */
29
30 #define THREADS_TOTAL          15
31 #define THREADS_CONCURRENT_MAX 5
32
33 #define BUFFER_SIZE            5000000   /* Amount of data to transfer */
34 #define PACKET_MAX_SIZE        8192      /* Max transfer unit */
35 #define PACKET_MIN_SIZE        1         /* Min transfer unit */
36
37 #define TOTAL_PAUSE_TIME_MS    3000      /* Total time to spend *not* reading or writing */
38 #define PAUSE_MIN_LENGTH_MS    10        /* Min pause unit */
39 #define PAUSE_MAX_LENGTH_MS    200       /* Max pause unit */
40
41 /* Calculations to determine the probability of pausing for
42  * each packet processed. No user serviceable parts inside. */
43
44 #define PROBABILITY_MULTIPLIER 1000000   /* For fixed-point fractions */
45 #define PACKET_AVG_SIZE        (PACKET_MIN_SIZE + ((PACKET_MAX_SIZE - PACKET_MIN_SIZE) / 2))
46 #define PAUSE_AVG_LENGTH_MS    (PAUSE_MIN_LENGTH_MS + ((PAUSE_MAX_LENGTH_MS - PAUSE_MIN_LENGTH_MS) / 2))
47 #define NUM_PAUSES             (TOTAL_PAUSE_TIME_MS / PAUSE_AVG_LENGTH_MS)
48 #define TOTAL_EXPECTED_PACKETS (BUFFER_SIZE / PACKET_AVG_SIZE)
49 #define TOTAL_EXPECTED_EVENTS  (TOTAL_EXPECTED_PACKETS * 2)  /* Account for both reads and writes */
50 #define PAUSE_PROBABILITY      ((NUM_PAUSES * PROBABILITY_MULTIPLIER) / TOTAL_EXPECTED_EVENTS)
51
52 #include "test-common.c"
53
54 typedef struct
55 {
56   gint offset;
57   gint len;
58 }
59 TransferInfo;
60
61 static guchar            *buffer                 = NULL;
62
63 static GStaticMutex       global_mutex           = G_STATIC_MUTEX_INIT;
64
65 static gint               threads_started        = 0;
66 static gint               threads_running        = 0;
67 static gint               threads_ended          = 0;
68
69 static void
70 subthread_main (void)
71 {
72   FlowFileIO    *file_io;
73   TransferInfo   transfer_info = { 0, 0 };
74   gchar         *file_name;
75   guchar         temp_buffer [PACKET_MAX_SIZE];
76   gboolean       result;
77   GError        *error = NULL;
78
79   test_print ("Subthread opening file\n");
80
81   file_name = g_strdup_printf ("test-file-io-scratch-%p-%08x", g_thread_self (), g_random_int ());
82   file_io = flow_file_io_new ();
83   result = flow_file_io_sync_create (file_io, file_name, FLOW_READ_ACCESS | FLOW_WRITE_ACCESS, TRUE,
84                                      FLOW_READ_ACCESS | FLOW_WRITE_ACCESS,
85                                      FLOW_NO_ACCESS,
86                                      FLOW_NO_ACCESS,
87                                      &error);
88
89   if (!result)
90   {
91     test_end (TEST_RESULT_FAILED, "failed to create scratch file");
92     g_error_free (error);
93     g_free (file_name);
94     return;
95   }
96
97   test_print ("Subthread opened file\n");
98
99   transfer_info.offset = 0;
100
101   while (transfer_info.len < BUFFER_SIZE)
102   {
103     gint op = g_random_int_range (0, 3);
104
105     g_assert (transfer_info.offset <= transfer_info.len);
106
107     if (op == 0)
108     {
109       gint len;
110
111       /* Append some data (seek to EOF if not already there) */
112
113       if (transfer_info.offset < transfer_info.len)
114       {
115         test_print ("Append: Seeking to EOF\n");
116         flow_file_io_seek (file_io, FLOW_OFFSET_ANCHOR_END, 0);
117       }
118
119       len = g_random_int_range (PACKET_MIN_SIZE, PACKET_MAX_SIZE);
120       len = MIN (len, BUFFER_SIZE - transfer_info.len);
121
122       test_print ("Append: Appending %d bytes\n", len);
123
124       flow_io_sync_write (FLOW_IO (file_io), buffer + transfer_info.len, len, NULL);
125
126       transfer_info.len += len;
127       transfer_info.offset = transfer_info.len;
128     }
129     else if (op == 1 && transfer_info.len > 0)
130     {
131       gint len;
132
133       /* Read some data (seek back if at EOF) */
134
135       if (transfer_info.offset == transfer_info.len)
136       {
137         gint offset = g_random_int_range (0, transfer_info.len);
138
139         test_print ("Read: Seeking to %d\n", offset);
140         flow_file_io_seek_to (file_io, offset);
141         transfer_info.offset = offset;
142       }
143
144       len = g_random_int_range (PACKET_MIN_SIZE, PACKET_MAX_SIZE);
145       len = MIN (len, transfer_info.len - transfer_info.offset);
146
147       test_print ("Read: Reading %d bytes\n", len);
148
149       /* TODO: Verify return value? */
150       flow_io_sync_read_exact (FLOW_IO (file_io), temp_buffer, len, NULL);
151
152       if (memcmp (temp_buffer, buffer + transfer_info.offset, len))
153         test_end (TEST_RESULT_FAILED, "Data verification error");
154
155       test_print ("Verified %d bytes ok\n", len);
156
157       transfer_info.offset += len;
158     }
159     else if (transfer_info.len > 0)
160     {
161       gint offset = g_random_int_range (0, transfer_info.len);
162
163       /* Seek to random offset */
164
165       test_print ("Seek: Seeking to %d\n", offset);
166
167       flow_file_io_seek_to (file_io, offset);
168       transfer_info.offset = offset;
169     }
170   }
171
172   test_print ("Subthread disconnecting\n");
173   flow_file_io_sync_close (file_io, NULL);
174   test_print ("Subthread disconnected\n");
175
176   g_object_unref (file_io);
177   test_print ("Subthread cleaned up\n");
178
179   threads_ended++;
180   threads_running--;
181
182   remove (file_name);
183   g_free (file_name);
184 }
185
186 static gboolean
187 spawn_subthread (void)
188 {
189   gboolean run_again = TRUE;
190
191   g_static_mutex_lock (&global_mutex);
192
193   if (threads_ended == THREADS_TOTAL)
194   {
195     test_quit_main_loop ();
196     run_again = FALSE;
197   }
198   else if (threads_started == THREADS_TOTAL ||
199            threads_running == THREADS_CONCURRENT_MAX)
200   {
201     /* Wait for threads to finish */
202   }
203   else
204   {
205     threads_started++;
206     threads_running++;
207
208     test_print ("Spawning new subthread\n");
209     g_thread_create ((GThreadFunc) subthread_main, NULL, FALSE, NULL);
210   }
211
212   g_static_mutex_unlock (&global_mutex);
213
214   return TRUE;
215 }
216
217 static void
218 long_test (void)
219 {
220   guint id;
221
222   test_print ("Long test begin\n");
223
224   id = g_timeout_add (250, (GSourceFunc) spawn_subthread, NULL);
225   test_run_main_loop ();
226   g_source_remove (id);
227
228   test_print ("Long test end\n");
229 }
230
231 static void
232 test_run (void)
233 {
234   gint i;
235
236   if (!g_thread_supported ())
237     g_thread_init (NULL);
238
239   g_random_set_seed (time (NULL));
240
241   /* Set up a buffer with random data */
242
243   buffer = g_malloc (BUFFER_SIZE);
244
245   for (i = 0; i < BUFFER_SIZE; )
246   {
247     guchar *p = buffer + i;
248
249     if (i < BUFFER_SIZE - 4)
250     {
251       *((guint32 *) p) = g_random_int ();
252       i += 4;
253     }
254     else
255     {
256       *p = (guchar) g_random_int ();
257       i++;
258     }
259   }
260
261   long_test ();
262
263   g_free (buffer);
264   buffer = NULL;
265 }
Note: See TracBrowser for help on using the browser.