RSS

(root)/calliope : /tests/library-test.c (revision 451)

Line Revision Contents
1 185 /*  Calliope Music Player
2  *  Copyright 2005-09 Sam Thursfield <ssssam gmail.com>
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15 356  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 185  */
17 356
18 185 #include <glib.h>
19 #include <glib/gstdio.h>
20 #include <gtk/gtk.h>
21 337 #include "calliope-core.h"
22 185 #include "conftool.h"
23 #include "library.h"
24 451 #include "library-private.h"
25 185 #include "test-utils.h"
26 #include "musicsource-tests.h"
27
28 356 #ifndef LIBRARY_DISABLE
29 185 static MusicSource *source_create_func() {
30         // If the db is open by another sqlite process, that produces some really confusing errors.
31         if (g_file_test(TEST_DB_PATH, G_FILE_TEST_EXISTS)) {
32                 int result = g_unlink(TEST_DB_PATH);
33                 if (result!=0)
34                         g_error("Unable to delete %s - this file is probably in use by another process.\n", TEST_DB_PATH);
35         }
36 356
37 185         MusicSource *library = library_new(TEST_DB_PATH);
38         return library;
39 };
40
41
42 // FIXME: this test can take a while.
43 //
44 static void concurrency() {
45         // Test for what happens when the database is shared between two calliopes! Note that this is
46         // unsupported but it's nice to be able to present a dialog to the user who attempts it, rather
47         // than crashing traumatically.
48 356
49         // Thread state is tracked using g_atomic_int functions.
50 185         typedef enum {
51                 STATE_MAIN_HAS_OPENED_DATABASE,
52                 STATE_HOG_HAS_OPENED_DATABASE,
53                 STATE_MAIN_RECEIVED_BUSY,
54                 STATE_HOG_RECEIVED_BUSY,
55                 STATE_MAIN_FINISHED,
56                 STATE_HOG_FINISHED
57         } State;
58         int state = STATE_MAIN_HAS_OPENED_DATABASE;
59 356
60 185         #define WAIT_STATE(n) \
61                 while (g_atomic_int_get(&state) != n) \
62                                 g_usleep (10000 /* 10ms */);
63 356
64 185         gboolean main_busy_handler (Library *library, double secs, const char *message, void *data) {
65                 if (g_atomic_int_get(&state)!=STATE_HOG_HAS_OPENED_DATABASE)
66                         return TRUE;
67                 g_atomic_int_inc (&state);      // State = STATE_MAIN_RECEIVED_BUSY
68                 //printf ("main: busy - %f, %s.\n", secs, message); fflush (stdout);
69                 return TRUE;
70         };
71 356
72 185         gboolean hog_busy_handler (Library *library, double secs, const char *message, void *data) {
73                 // Wait for main to receive busy first.
74                 if (g_atomic_int_get(&state)!=STATE_MAIN_RECEIVED_BUSY)
75                         return TRUE;
76                 g_atomic_int_inc (&state);      // State = STATE_HOG_RECEIVED_BUSY
77                 //printf ("hog: busy - %f, %s.\n", secs, message); fflush (stdout);
78                 return TRUE;
79         };
80 356
81 185         void *database_hog_thread(const void *data) {
82                 MusicSource *library = library_new (TEST_DB_PATH);
83                 g_signal_connect (library, "busy", G_CALLBACK(hog_busy_handler), NULL);
84                 g_assert_cmpint (g_atomic_int_get (&state), ==, STATE_MAIN_HAS_OPENED_DATABASE);
85 356
86 185                 //printf ("hog: Opened db.\n"); fflush (stdout);
87                 int file_id = test_add_file (library, NULL, 0, 1);
88                 g_assert_cmpint (file_id, ==, 1);
89                 g_atomic_int_inc (&state);      // State = HOG_HAS_OPENED_DATABASE
90
91                 int bitrate = 0;
92                 while (g_atomic_int_get(&state)!=STATE_MAIN_FINISHED) {
93 356                         music_source_update_entry_property (library, ENTRY_TYPE_FILE, 1,
94 185                                                             FILE_BITRATE, GINT_TO_POINTER(bitrate));
95                         g_usleep (1000 /* 1ms */);
96                         bitrate++;
97                 };
98 356
99                 g_atomic_int_inc (&state);      // State = STATE_HOG_FINISHED
100 185                 //printf ("hog: Closing db.\n"); fflush (stdout);
101                 g_object_unref (library);
102                 return 0;
103         };
104 356
105 185         MusicSource *library = source_create_func();
106         g_signal_connect (library, "busy", G_CALLBACK(main_busy_handler), NULL);
107 356
108 185         GError *error = NULL;
109 350         g_thread_create ((GThreadFunc)database_hog_thread, NULL, FALSE, &error);
110 356         g_assert_no_error (error);
111
112 185         gdk_threads_leave ();
113         WAIT_STATE (STATE_HOG_HAS_OPENED_DATABASE);
114         gdk_threads_enter ();
115 356
116 185         while (g_atomic_int_get(&state)!=STATE_HOG_RECEIVED_BUSY) {
117                 // Don't use music_source_query_entry to avoid the cache.
118 356                 db_expression_printf (LIBRARY(library), NULL,  "SELECT bitrate FROM _file WHERE id=1");
119 185                 gdk_threads_leave ();
120                 g_usleep (1000 /* 1ms */);
121                 gdk_threads_enter ();
122         };
123
124         g_atomic_int_inc (&state);      // State = STATE_FINISHED
125         gdk_threads_leave ();
126         WAIT_STATE (STATE_HOG_FINISHED);
127         gdk_threads_enter ();
128
129         //printf ("main: Closing db."); fflush (stdout);
130         g_object_unref(library);
131 };
132 356 #endif
133 185
134 int main(int argc, char *argv[]) {
135 356         #ifndef LIBRARY_DISABLE
136 185         // I think we should call gtk_test_init really, even though we only
137         // use GtkTreeModel-derived interfaces here which in practice work
138 356         // okay without.
139 185         g_thread_init (NULL);
140         gdk_threads_enter ();
141         gtk_test_init (&argc, &argv, NULL);
142 337         calliope_core_init ();
143 356
144 185         music_source_tests_register("library", source_create_func);
145         if (g_test_slow())
146                 g_test_add_func("/library/Concurrency", concurrency);
147
148         int result=g_test_run();
149         //g_unlink(TEST_DB_PATH);
150         gdk_threads_leave ();
151 356
152 185         return result;
153 356         #endif
154 185 }

Loggerhead is a web-based interface for Bazaar branches