Release 1.5.29.
[wine] / dlls / qmgr / tests / job.c
1 /*
2  * Unit test suite for Background Copy Job Interface
3  *
4  * Copyright 2007 Google (Roy Shea)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22
23 #define COBJMACROS
24
25 #include "wine/test.h"
26 #include "bits.h"
27 #include "initguid.h"
28
29 /* Globals used by many tests */
30 static const WCHAR test_displayName[] = {'T', 'e', 's', 't', 0};
31 static WCHAR test_remotePathA[MAX_PATH];
32 static WCHAR test_remotePathB[MAX_PATH];
33 static WCHAR test_localPathA[MAX_PATH];
34 static WCHAR test_localPathB[MAX_PATH];
35 static IBackgroundCopyManager *test_manager;
36 static IBackgroundCopyJob *test_job;
37 static GUID test_jobId;
38 static BG_JOB_TYPE test_type;
39
40 static VOID init_paths(void)
41 {
42     WCHAR tmpDir[MAX_PATH];
43     WCHAR prefix[] = {'q', 'm', 'g', 'r', 0};
44
45     GetTempPathW(MAX_PATH, tmpDir);
46
47     GetTempFileNameW(tmpDir, prefix, 0, test_localPathA);
48     GetTempFileNameW(tmpDir, prefix, 0, test_localPathB);
49     GetTempFileNameW(tmpDir, prefix, 0, test_remotePathA);
50     GetTempFileNameW(tmpDir, prefix, 0, test_remotePathB);
51 }
52
53 /* Generic test setup */
54 static BOOL setup(void)
55 {
56     HRESULT hres;
57
58     test_manager = NULL;
59     test_job = NULL;
60     memset(&test_jobId, 0, sizeof test_jobId);
61     test_type = BG_JOB_TYPE_DOWNLOAD;
62
63     hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL,
64                             CLSCTX_LOCAL_SERVER,
65                             &IID_IBackgroundCopyManager,
66                             (void **) &test_manager);
67     if(hres != S_OK)
68         return FALSE;
69
70     hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayName,
71                                             test_type, &test_jobId, &test_job);
72     if(hres != S_OK)
73     {
74         IBackgroundCopyManager_Release(test_manager);
75         return FALSE;
76     }
77
78     return TRUE;
79 }
80
81 /* Generic test cleanup */
82 static void teardown(void)
83 {
84     IBackgroundCopyJob_Release(test_job);
85     IBackgroundCopyManager_Release(test_manager);
86 }
87
88 /* FIXME: Remove when Wine has implemented this */
89 DEFINE_GUID(CLSID_BackgroundCopyManager2_0, 0x6d18ad12, 0xbde3, 0x4393, 0xb3,0x11, 0x09,0x9c,0x34,0x6e,0x6d,0xf9);
90
91 static BOOL check_bits20(void)
92 {
93     HRESULT hres;
94     IBackgroundCopyManager *manager;
95     BOOL ret = TRUE;
96
97     hres = CoCreateInstance(&CLSID_BackgroundCopyManager2_0, NULL,
98                             CLSCTX_LOCAL_SERVER,
99                             &IID_IBackgroundCopyManager,
100                             (void **) &manager);
101
102     if (hres == REGDB_E_CLASSNOTREG)
103     {
104         ret = FALSE;
105
106         /* FIXME: Wine implements 2.0 functionality but doesn't advertise 2.0
107          *
108          * Remove when Wine is fixed
109          */
110         if (setup())
111         {
112             HRESULT hres2;
113
114             hres2 = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
115                                                test_localPathA);
116             if (hres2 == S_OK)
117             {
118                 trace("Running on Wine, claim 2.0 is present\n");
119                 ret = TRUE;
120             }
121             teardown();
122         }
123     }
124
125     if (manager)
126         IBackgroundCopyManager_Release(manager);
127
128     return ret;
129 }
130
131 /* Test that the jobId is properly set */
132 static void test_GetId(void)
133 {
134     HRESULT hres;
135     GUID tmpId;
136
137     hres = IBackgroundCopyJob_GetId(test_job, &tmpId);
138     ok(hres == S_OK, "GetId failed: %08x\n", hres);
139     if(hres != S_OK)
140     {
141         skip("Unable to get ID of test_job.\n");
142         return;
143     }
144     ok(memcmp(&tmpId, &test_jobId, sizeof tmpId) == 0, "Got incorrect GUID\n");
145 }
146
147 /* Test that the type is properly set */
148 static void test_GetType(void)
149 {
150     HRESULT hres;
151     BG_JOB_TYPE type;
152
153     hres = IBackgroundCopyJob_GetType(test_job, &type);
154     ok(hres == S_OK, "GetType failed: %08x\n", hres);
155     if(hres != S_OK)
156     {
157         skip("Unable to get type of test_job.\n");
158         return;
159     }
160     ok(type == test_type, "Got incorrect type\n");
161 }
162
163 /* Test that the display name is properly set */
164 static void test_GetName(void)
165 {
166     HRESULT hres;
167     LPWSTR displayName;
168
169     hres = IBackgroundCopyJob_GetDisplayName(test_job, &displayName);
170     ok(hres == S_OK, "GetName failed: %08x\n", hres);
171     if(hres != S_OK)
172     {
173         skip("Unable to get display name of test_job.\n");
174         return;
175     }
176     ok(lstrcmpW(displayName, test_displayName) == 0, "Got incorrect type\n");
177     CoTaskMemFree(displayName);
178 }
179
180 /* Test adding a file */
181 static void test_AddFile(void)
182 {
183     HRESULT hres;
184
185     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
186                                       test_localPathA);
187     ok(hres == S_OK, "First call to AddFile failed: 0x%08x\n", hres);
188     if (hres != S_OK)
189     {
190         skip("Unable to add first file to job\n");
191         return;
192     }
193
194     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB,
195                                       test_localPathB);
196     ok(hres == S_OK, "Second call to AddFile failed: 0x%08x\n", hres);
197 }
198
199 /* Test adding a set of files */
200 static void test_AddFileSet(void)
201 {
202     HRESULT hres;
203     BG_FILE_INFO files[2] =
204         {
205             {test_remotePathA, test_localPathA},
206             {test_remotePathB, test_localPathB}
207         };
208     hres = IBackgroundCopyJob_AddFileSet(test_job, 2, files);
209     ok(hres == S_OK, "AddFileSet failed: 0x%08x\n", hres);
210 }
211
212 /* Test creation of a job enumerator */
213 static void test_EnumFiles(void)
214 {
215     HRESULT hres;
216     IEnumBackgroundCopyFiles *enumFiles;
217     ULONG res;
218
219     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
220                                       test_localPathA);
221     if (hres != S_OK)
222     {
223         skip("Unable to add file to job\n");
224         return;
225     }
226
227     hres = IBackgroundCopyJob_EnumFiles(test_job, &enumFiles);
228     ok(hres == S_OK, "EnumFiles failed: 0x%08x\n", hres);
229     if(hres != S_OK)
230     {
231         skip("Unable to create file enumerator.\n");
232         return;
233     }
234
235     res = IEnumBackgroundCopyFiles_Release(enumFiles);
236     ok(res == 0, "Bad ref count on release: %u\n", res);
237 }
238
239 /* Test getting job progress */
240 static void test_GetProgress_preTransfer(void)
241 {
242     HRESULT hres;
243     BG_JOB_PROGRESS progress;
244
245     hres = IBackgroundCopyJob_GetProgress(test_job, &progress);
246     ok(hres == S_OK, "GetProgress failed: 0x%08x\n", hres);
247     if (hres != S_OK)
248     {
249         skip("Unable to get job progress\n");
250         teardown();
251         return;
252     }
253
254     ok(progress.BytesTotal == 0, "Incorrect BytesTotal: %x%08x\n",
255        (DWORD)(progress.BytesTotal >> 32), (DWORD)progress.BytesTotal);
256     ok(progress.BytesTransferred == 0, "Incorrect BytesTransferred: %x%08x\n",
257        (DWORD)(progress.BytesTransferred >> 32), (DWORD)progress.BytesTransferred);
258     ok(progress.FilesTotal == 0, "Incorrect FilesTotal: %u\n", progress.FilesTotal);
259     ok(progress.FilesTransferred == 0, "Incorrect FilesTransferred %u\n", progress.FilesTransferred);
260 }
261
262 /* Test getting job state */
263 static void test_GetState(void)
264 {
265     HRESULT hres;
266     BG_JOB_STATE state;
267
268     state = BG_JOB_STATE_ERROR;
269     hres = IBackgroundCopyJob_GetState(test_job, &state);
270     ok(hres == S_OK, "GetState failed: 0x%08x\n", hres);
271     if (hres != S_OK)
272     {
273         skip("Unable to get job state\n");
274         return;
275     }
276     ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state);
277 }
278
279 /* Test resuming a job */
280 static void test_ResumeEmpty(void)
281 {
282     HRESULT hres;
283     BG_JOB_STATE state;
284
285     hres = IBackgroundCopyJob_Resume(test_job);
286     ok(hres == BG_E_EMPTY, "Resume failed to return BG_E_EMPTY error: 0x%08x\n", hres);
287     if (hres != BG_E_EMPTY)
288     {
289         skip("Failed calling resume job\n");
290         return;
291     }
292
293     state = BG_JOB_STATE_ERROR;
294     hres = IBackgroundCopyJob_GetState(test_job, &state);
295     if (hres != S_OK)
296     {
297         skip("Unable to get job state\n");
298         return;
299     }
300     ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state);
301 }
302
303 static void makeFile(WCHAR *name, const char *contents)
304 {
305     HANDLE file;
306     DWORD w, len = strlen(contents);
307
308     DeleteFileW(name);
309     file = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
310                        FILE_ATTRIBUTE_NORMAL, NULL);
311     ok(file != INVALID_HANDLE_VALUE, "CreateFile\n");
312     ok(WriteFile(file, contents, len, &w, NULL), "WriteFile\n");
313     CloseHandle(file);
314 }
315
316 static void compareFiles(WCHAR *n1, WCHAR *n2)
317 {
318     char b1[256];
319     char b2[256];
320     DWORD s1, s2;
321     HANDLE f1, f2;
322
323     f1 = CreateFileW(n1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
324                      FILE_ATTRIBUTE_NORMAL, NULL);
325     ok(f1 != INVALID_HANDLE_VALUE, "CreateFile\n");
326
327     f2 = CreateFileW(n2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
328                      FILE_ATTRIBUTE_NORMAL, NULL);
329     ok(f2 != INVALID_HANDLE_VALUE, "CreateFile\n");
330
331     /* Neither of these files is very big */
332     ok(ReadFile(f1, b1, sizeof b1, &s1, NULL), "ReadFile\n");
333     ok(ReadFile(f2, b2, sizeof b2, &s2, NULL), "ReadFile\n");
334
335     CloseHandle(f1);
336     CloseHandle(f2);
337
338     ok(s1 == s2, "Files differ in length\n");
339     ok(memcmp(b1, b2, s1) == 0, "Files differ in contents\n");
340 }
341
342 /* Test a complete transfer for local files */
343 static void test_CompleteLocal(void)
344 {
345     static const int timeout_sec = 30;
346     HRESULT hres;
347     BG_JOB_STATE state;
348     int i;
349
350     DeleteFileW(test_localPathA);
351     DeleteFileW(test_localPathB);
352     makeFile(test_remotePathA, "This is a WINE test file for BITS\n");
353     makeFile(test_remotePathB, "This is another WINE test file for BITS\n");
354
355     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
356                                       test_localPathA);
357     if (hres != S_OK)
358     {
359         skip("Unable to add file to job\n");
360         return;
361     }
362
363     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB,
364                                       test_localPathB);
365     if (hres != S_OK)
366     {
367         skip("Unable to add file to job\n");
368         return;
369     }
370
371     hres = IBackgroundCopyJob_Resume(test_job);
372     ok(hres == S_OK, "IBackgroundCopyJob_Resume\n");
373
374     for (i = 0; i < timeout_sec; ++i)
375     {
376         hres = IBackgroundCopyJob_GetState(test_job, &state);
377         ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
378         ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING
379            || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED,
380            "Bad state: %d\n", state);
381         if (state == BG_JOB_STATE_TRANSFERRED)
382             break;
383         Sleep(1000);
384     }
385
386     ok(i < timeout_sec, "BITS jobs timed out\n");
387     hres = IBackgroundCopyJob_Complete(test_job);
388     ok(hres == S_OK, "IBackgroundCopyJob_Complete\n");
389     hres = IBackgroundCopyJob_GetState(test_job, &state);
390     ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
391     ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state);
392
393     compareFiles(test_remotePathA, test_localPathA);
394     compareFiles(test_remotePathB, test_localPathB);
395
396     ok(DeleteFileW(test_remotePathA), "DeleteFile\n");
397     ok(DeleteFileW(test_remotePathB), "DeleteFile\n");
398     DeleteFileW(test_localPathA);
399     DeleteFileW(test_localPathB);
400 }
401
402 /* Test a complete transfer for local files */
403 static void test_CompleteLocalURL(void)
404 {
405     static const WCHAR prot[] = {'f','i','l','e',':','/','/', 0};
406     static const int timeout_sec = 30;
407     WCHAR *urlA, *urlB;
408     HRESULT hres;
409     BG_JOB_STATE state;
410     int i;
411
412     DeleteFileW(test_localPathA);
413     DeleteFileW(test_localPathB);
414     makeFile(test_remotePathA, "This is a WINE test file for BITS\n");
415     makeFile(test_remotePathB, "This is another WINE test file for BITS\n");
416
417     urlA = HeapAlloc(GetProcessHeap(), 0,
418                      (7 + lstrlenW(test_remotePathA) + 1) * sizeof urlA[0]);
419     urlB = HeapAlloc(GetProcessHeap(), 0,
420                      (7 + lstrlenW(test_remotePathB) + 1) * sizeof urlB[0]);
421     if (!urlA || !urlB)
422     {
423         skip("Unable to allocate memory for URLs\n");
424         HeapFree(GetProcessHeap(), 0, urlA);
425         HeapFree(GetProcessHeap(), 0, urlB);
426         return;
427     }
428
429     lstrcpyW(urlA, prot);
430     lstrcatW(urlA, test_remotePathA);
431     lstrcpyW(urlB, prot);
432     lstrcatW(urlB, test_remotePathB);
433
434     hres = IBackgroundCopyJob_AddFile(test_job, urlA, test_localPathA);
435     if (hres != S_OK)
436     {
437         skip("Unable to add file to job\n");
438         HeapFree(GetProcessHeap(), 0, urlA);
439         HeapFree(GetProcessHeap(), 0, urlB);
440         return;
441     }
442
443     hres = IBackgroundCopyJob_AddFile(test_job, urlB, test_localPathB);
444     if (hres != S_OK)
445     {
446         skip("Unable to add file to job\n");
447         HeapFree(GetProcessHeap(), 0, urlA);
448         HeapFree(GetProcessHeap(), 0, urlB);
449         return;
450     }
451
452     hres = IBackgroundCopyJob_Resume(test_job);
453     ok(hres == S_OK, "IBackgroundCopyJob_Resume\n");
454
455     for (i = 0; i < timeout_sec; ++i)
456     {
457         hres = IBackgroundCopyJob_GetState(test_job, &state);
458         ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
459         ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING
460            || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED,
461            "Bad state: %d\n", state);
462         if (state == BG_JOB_STATE_TRANSFERRED)
463             break;
464         Sleep(1000);
465     }
466
467     ok(i < timeout_sec, "BITS jobs timed out\n");
468     hres = IBackgroundCopyJob_Complete(test_job);
469     ok(hres == S_OK, "IBackgroundCopyJob_Complete\n");
470     hres = IBackgroundCopyJob_GetState(test_job, &state);
471     ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
472     ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state);
473
474     compareFiles(test_remotePathA, test_localPathA);
475     compareFiles(test_remotePathB, test_localPathB);
476
477     ok(DeleteFileW(test_remotePathA), "DeleteFile\n");
478     ok(DeleteFileW(test_remotePathB), "DeleteFile\n");
479     DeleteFileW(test_localPathA);
480     DeleteFileW(test_localPathB);
481
482     HeapFree(GetProcessHeap(), 0, urlA);
483     HeapFree(GetProcessHeap(), 0, urlB);
484 }
485
486 typedef void (*test_t)(void);
487
488 START_TEST(job)
489 {
490     static const test_t tests[] = {
491         test_GetId,
492         test_GetType,
493         test_GetName,
494         test_GetProgress_preTransfer,
495         test_GetState,
496         test_ResumeEmpty,
497         0
498     };
499     static const test_t tests_bits20[] = {
500         test_AddFile,
501         test_AddFileSet,
502         test_EnumFiles,
503         test_CompleteLocal,
504         test_CompleteLocalURL,
505         0
506     };
507     const test_t *test;
508
509     init_paths();
510
511     CoInitialize(NULL);
512
513     for (test = tests; *test; ++test)
514     {
515         /* Keep state separate between tests. */
516         if (!setup())
517         {
518             skip("Unable to setup test\n");
519             break;
520         }
521         (*test)();
522         teardown();
523     }
524
525     if (check_bits20())
526     {
527         for (test = tests_bits20; *test; ++test)
528         {
529             /* Keep state separate between tests. */
530             if (!setup())
531             {
532                 skip("Unable to setup test\n");
533                 break;
534             }
535             (*test)();
536             teardown();
537         }
538     }
539     else
540     {
541         win_skip("Tests need BITS 2.0 or higher\n");
542     }
543
544     CoUninitialize();
545 }