xref: /reactos/modules/rostests/winetests/qmgr/job.c (revision 64daf542)
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 WIN32_NO_STATUS
24 #define _INC_WINDOWS
25 #define COM_NO_WINDOWS_H
26 
27 #define COBJMACROS
28 
29 #include <wine/test.h>
30 #include <objbase.h>
31 #include <bits.h>
32 #include <initguid.h>
33 #include <bits2_0.h>
34 #include <bits2_5.h>
35 
36 /* Globals used by many tests */
37 static const WCHAR test_displayName[] = {'T', 'e', 's', 't', 0};
38 static WCHAR test_remotePathA[MAX_PATH];
39 static WCHAR test_remotePathB[MAX_PATH];
40 static WCHAR test_localPathA[MAX_PATH];
41 static WCHAR test_localPathB[MAX_PATH];
42 static IBackgroundCopyManager *test_manager;
43 static IBackgroundCopyJob *test_job;
44 static GUID test_jobId;
45 static BG_JOB_TYPE test_type;
46 
47 static HRESULT test_create_manager(void)
48 {
49     HRESULT hres;
50     IBackgroundCopyManager *manager = NULL;
51 
52     /* Creating BITS instance */
53     hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, CLSCTX_LOCAL_SERVER,
54                             &IID_IBackgroundCopyManager, (void **) &manager);
55 
56     if(hres == HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED)) {
57         win_skip("Needed Service is disabled\n");
58         return hres;
59     }
60 
61     if (hres == S_OK)
62         IBackgroundCopyManager_Release(manager);
63 
64     return hres;
65 }
66 
67 static void init_paths(void)
68 {
69     WCHAR tmpDir[MAX_PATH];
70     WCHAR prefix[] = {'q', 'm', 'g', 'r', 0};
71 
72     GetTempPathW(MAX_PATH, tmpDir);
73 
74     GetTempFileNameW(tmpDir, prefix, 0, test_localPathA);
75     GetTempFileNameW(tmpDir, prefix, 0, test_localPathB);
76     GetTempFileNameW(tmpDir, prefix, 0, test_remotePathA);
77     GetTempFileNameW(tmpDir, prefix, 0, test_remotePathB);
78 }
79 
80 /* Generic test setup */
81 static BOOL setup(void)
82 {
83     HRESULT hres;
84 
85     test_manager = NULL;
86     test_job = NULL;
87     memset(&test_jobId, 0, sizeof test_jobId);
88     test_type = BG_JOB_TYPE_DOWNLOAD;
89 
90     hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL,
91                             CLSCTX_LOCAL_SERVER,
92                             &IID_IBackgroundCopyManager,
93                             (void **) &test_manager);
94     if(hres != S_OK)
95         return FALSE;
96 
97     hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayName,
98                                             test_type, &test_jobId, &test_job);
99     if(hres != S_OK)
100     {
101         IBackgroundCopyManager_Release(test_manager);
102         return FALSE;
103     }
104 
105     return TRUE;
106 }
107 
108 /* Generic test cleanup */
109 static void teardown(void)
110 {
111     IBackgroundCopyJob_Cancel(test_job);
112     IBackgroundCopyJob_Release(test_job);
113     IBackgroundCopyManager_Release(test_manager);
114 }
115 
116 static BOOL check_bits20(void)
117 {
118     HRESULT hres;
119     IBackgroundCopyManager *manager;
120     IBackgroundCopyJob *job, *job3;
121 
122     hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL,
123                             CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager,
124                             (void **)&manager);
125     if (hres != S_OK) return FALSE;
126 
127     hres = IBackgroundCopyManager_CreateJob(manager, test_displayName, test_type, &test_jobId, &job);
128     if (hres != S_OK)
129     {
130         IBackgroundCopyManager_Release(manager);
131         return FALSE;
132     }
133 
134     hres = IBackgroundCopyJob_QueryInterface(job, &IID_IBackgroundCopyJob3, (void **)&job3);
135     IBackgroundCopyJob_Cancel(job);
136     IBackgroundCopyJob_Release(job);
137     if (hres != S_OK)
138     {
139         IBackgroundCopyManager_Release(manager);
140         return FALSE;
141     }
142 
143     IBackgroundCopyJob_Release(job3);
144     IBackgroundCopyManager_Release(manager);
145     return TRUE;
146 }
147 
148 static BOOL check_bits25(void)
149 {
150     HRESULT hres;
151     IBackgroundCopyManager *manager;
152     IBackgroundCopyJob *job;
153     IBackgroundCopyJobHttpOptions *options;
154 
155     hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL,
156                             CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager,
157                             (void **)&manager);
158     if (hres != S_OK) return FALSE;
159 
160     hres = IBackgroundCopyManager_CreateJob(manager, test_displayName, test_type, &test_jobId, &job);
161     if (hres != S_OK)
162     {
163         IBackgroundCopyManager_Release(manager);
164         return FALSE;
165     }
166 
167     hres = IBackgroundCopyJob_QueryInterface(job, &IID_IBackgroundCopyJobHttpOptions, (void **)&options);
168     IBackgroundCopyJob_Cancel(job);
169     IBackgroundCopyJob_Release(job);
170     if (hres != S_OK)
171     {
172         IBackgroundCopyManager_Release(manager);
173         return FALSE;
174     }
175 
176     IBackgroundCopyJobHttpOptions_Release(options);
177     IBackgroundCopyManager_Release(manager);
178     return TRUE;
179 }
180 
181 /* Test that the jobId is properly set */
182 static void test_GetId(void)
183 {
184     HRESULT hres;
185     GUID tmpId;
186 
187     hres = IBackgroundCopyJob_GetId(test_job, &tmpId);
188     ok(hres == S_OK, "GetId failed: %08x\n", hres);
189     ok(memcmp(&tmpId, &test_jobId, sizeof tmpId) == 0, "Got incorrect GUID\n");
190 }
191 
192 /* Test that the type is properly set */
193 static void test_GetType(void)
194 {
195     HRESULT hres;
196     BG_JOB_TYPE type;
197 
198     hres = IBackgroundCopyJob_GetType(test_job, &type);
199     ok(hres == S_OK, "GetType failed: %08x\n", hres);
200     ok(type == test_type, "Got incorrect type\n");
201 }
202 
203 /* Test that the display name is properly set */
204 static void test_GetName(void)
205 {
206     HRESULT hres;
207     LPWSTR displayName;
208 
209     hres = IBackgroundCopyJob_GetDisplayName(test_job, &displayName);
210     ok(hres == S_OK, "GetName failed: %08x\n", hres);
211     ok(lstrcmpW(displayName, test_displayName) == 0, "Got incorrect type\n");
212     CoTaskMemFree(displayName);
213 }
214 
215 /* Test adding a file */
216 static void test_AddFile(void)
217 {
218     HRESULT hres;
219 
220     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
221                                       test_localPathA);
222     ok(hres == S_OK, "First call to AddFile failed: 0x%08x\n", hres);
223 
224     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB,
225                                       test_localPathB);
226     ok(hres == S_OK, "Second call to AddFile failed: 0x%08x\n", hres);
227 }
228 
229 /* Test adding a set of files */
230 static void test_AddFileSet(void)
231 {
232     HRESULT hres;
233     BG_FILE_INFO files[2] =
234         {
235             {test_remotePathA, test_localPathA},
236             {test_remotePathB, test_localPathB}
237         };
238     hres = IBackgroundCopyJob_AddFileSet(test_job, 2, files);
239     ok(hres == S_OK, "AddFileSet failed: 0x%08x\n", hres);
240 }
241 
242 /* Test creation of a job enumerator */
243 static void test_EnumFiles(void)
244 {
245     HRESULT hres;
246     IEnumBackgroundCopyFiles *enumFiles;
247     ULONG res;
248 
249     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
250                                       test_localPathA);
251     ok(hres == S_OK, "got 0x%08x\n", hres);
252 
253     hres = IBackgroundCopyJob_EnumFiles(test_job, &enumFiles);
254     ok(hres == S_OK, "EnumFiles failed: 0x%08x\n", hres);
255 
256     res = IEnumBackgroundCopyFiles_Release(enumFiles);
257     ok(res == 0, "Bad ref count on release: %u\n", res);
258 }
259 
260 /* Test getting job progress */
261 static void test_GetProgress_preTransfer(void)
262 {
263     HRESULT hres;
264     BG_JOB_PROGRESS progress;
265 
266     hres = IBackgroundCopyJob_GetProgress(test_job, &progress);
267     ok(hres == S_OK, "GetProgress failed: 0x%08x\n", hres);
268 
269     ok(progress.BytesTotal == 0, "Incorrect BytesTotal: %s\n",
270        wine_dbgstr_longlong(progress.BytesTotal));
271     ok(progress.BytesTransferred == 0, "Incorrect BytesTransferred: %s\n",
272        wine_dbgstr_longlong(progress.BytesTransferred));
273     ok(progress.FilesTotal == 0, "Incorrect FilesTotal: %u\n", progress.FilesTotal);
274     ok(progress.FilesTransferred == 0, "Incorrect FilesTransferred %u\n", progress.FilesTransferred);
275 }
276 
277 /* Test getting job state */
278 static void test_GetState(void)
279 {
280     HRESULT hres;
281     BG_JOB_STATE state;
282 
283     state = BG_JOB_STATE_ERROR;
284     hres = IBackgroundCopyJob_GetState(test_job, &state);
285     ok(hres == S_OK, "GetState failed: 0x%08x\n", hres);
286     ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state);
287 }
288 
289 /* Test resuming a job */
290 static void test_ResumeEmpty(void)
291 {
292     HRESULT hres;
293     BG_JOB_STATE state;
294 
295     hres = IBackgroundCopyJob_Resume(test_job);
296     ok(hres == BG_E_EMPTY, "Resume failed to return BG_E_EMPTY error: 0x%08x\n", hres);
297 
298     state = BG_JOB_STATE_ERROR;
299     hres = IBackgroundCopyJob_GetState(test_job, &state);
300     ok(hres == S_OK, "got 0x%08x\n", hres);
301     ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state);
302 }
303 
304 static void makeFile(WCHAR *name, const char *contents)
305 {
306     HANDLE file;
307     DWORD w, len = strlen(contents);
308 
309     DeleteFileW(name);
310     file = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
311                        FILE_ATTRIBUTE_NORMAL, NULL);
312     ok(file != INVALID_HANDLE_VALUE, "CreateFile\n");
313     ok(WriteFile(file, contents, len, &w, NULL), "WriteFile\n");
314     CloseHandle(file);
315 }
316 
317 static void compareFiles(WCHAR *n1, WCHAR *n2)
318 {
319     char b1[256];
320     char b2[256];
321     DWORD s1, s2;
322     HANDLE f1, f2;
323 
324     f1 = CreateFileW(n1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
325                      FILE_ATTRIBUTE_NORMAL, NULL);
326     ok(f1 != INVALID_HANDLE_VALUE, "CreateFile\n");
327 
328     f2 = CreateFileW(n2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
329                      FILE_ATTRIBUTE_NORMAL, NULL);
330     ok(f2 != INVALID_HANDLE_VALUE, "CreateFile\n");
331 
332     /* Neither of these files is very big */
333     ok(ReadFile(f1, b1, sizeof b1, &s1, NULL), "ReadFile\n");
334     ok(ReadFile(f2, b2, sizeof b2, &s2, NULL), "ReadFile\n");
335 
336     CloseHandle(f1);
337     CloseHandle(f2);
338 
339     ok(s1 == s2, "Files differ in length\n");
340     ok(memcmp(b1, b2, s1) == 0, "Files differ in contents\n");
341 }
342 
343 /* Test a complete transfer for local files */
344 static void test_CompleteLocal(void)
345 {
346     static const int timeout_sec = 30;
347     HRESULT hres;
348     BG_JOB_STATE state;
349     int i;
350 
351     DeleteFileW(test_localPathA);
352     DeleteFileW(test_localPathB);
353     makeFile(test_remotePathA, "This is a WINE test file for BITS\n");
354     makeFile(test_remotePathB, "This is another WINE test file for BITS\n");
355 
356     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA,
357                                       test_localPathA);
358     ok(hres == S_OK, "got 0x%08x\n", hres);
359 
360     hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB,
361                                       test_localPathB);
362     ok(hres == S_OK, "got 0x%08x\n", hres);
363 
364     hres = IBackgroundCopyJob_Resume(test_job);
365     ok(hres == S_OK, "IBackgroundCopyJob_Resume\n");
366 
367     for (i = 0; i < timeout_sec; ++i)
368     {
369         hres = IBackgroundCopyJob_GetState(test_job, &state);
370         ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
371         ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING
372            || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED,
373            "Bad state: %d\n", state);
374         if (state == BG_JOB_STATE_TRANSFERRED)
375             break;
376         Sleep(1000);
377     }
378 
379     ok(i < timeout_sec, "BITS jobs timed out\n");
380     hres = IBackgroundCopyJob_Complete(test_job);
381     ok(hres == S_OK, "IBackgroundCopyJob_Complete\n");
382     hres = IBackgroundCopyJob_GetState(test_job, &state);
383     ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
384     ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state);
385 
386     compareFiles(test_remotePathA, test_localPathA);
387     compareFiles(test_remotePathB, test_localPathB);
388 
389     ok(DeleteFileW(test_remotePathA), "DeleteFile\n");
390     ok(DeleteFileW(test_remotePathB), "DeleteFile\n");
391     DeleteFileW(test_localPathA);
392     DeleteFileW(test_localPathB);
393 }
394 
395 /* Test a complete transfer for local files */
396 static void test_CompleteLocalURL(void)
397 {
398     static const WCHAR prot[] = {'f','i','l','e',':','/','/', 0};
399     static const int timeout_sec = 30;
400     WCHAR *urlA, *urlB;
401     HRESULT hres;
402     BG_JOB_STATE state;
403     int i;
404 
405     DeleteFileW(test_localPathA);
406     DeleteFileW(test_localPathB);
407     makeFile(test_remotePathA, "This is a WINE test file for BITS\n");
408     makeFile(test_remotePathB, "This is another WINE test file for BITS\n");
409 
410     urlA = HeapAlloc(GetProcessHeap(), 0,
411                      (7 + lstrlenW(test_remotePathA) + 1) * sizeof urlA[0]);
412     urlB = HeapAlloc(GetProcessHeap(), 0,
413                      (7 + lstrlenW(test_remotePathB) + 1) * sizeof urlB[0]);
414     if (!urlA || !urlB)
415     {
416         skip("Unable to allocate memory for URLs\n");
417         HeapFree(GetProcessHeap(), 0, urlA);
418         HeapFree(GetProcessHeap(), 0, urlB);
419         return;
420     }
421 
422     lstrcpyW(urlA, prot);
423     lstrcatW(urlA, test_remotePathA);
424     lstrcpyW(urlB, prot);
425     lstrcatW(urlB, test_remotePathB);
426 
427     hres = IBackgroundCopyJob_AddFile(test_job, urlA, test_localPathA);
428     ok(hres == S_OK, "got 0x%08x\n", hres);
429 
430     hres = IBackgroundCopyJob_AddFile(test_job, urlB, test_localPathB);
431     ok(hres == S_OK, "got 0x%08x\n", hres);
432 
433     hres = IBackgroundCopyJob_Resume(test_job);
434     ok(hres == S_OK, "IBackgroundCopyJob_Resume\n");
435 
436     for (i = 0; i < timeout_sec; ++i)
437     {
438         hres = IBackgroundCopyJob_GetState(test_job, &state);
439         ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
440         ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING
441            || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED,
442            "Bad state: %d\n", state);
443         if (state == BG_JOB_STATE_TRANSFERRED)
444             break;
445         Sleep(1000);
446     }
447 
448     ok(i < timeout_sec, "BITS jobs timed out\n");
449     hres = IBackgroundCopyJob_Complete(test_job);
450     ok(hres == S_OK, "IBackgroundCopyJob_Complete\n");
451     hres = IBackgroundCopyJob_GetState(test_job, &state);
452     ok(hres == S_OK, "IBackgroundCopyJob_GetState\n");
453     ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state);
454 
455     compareFiles(test_remotePathA, test_localPathA);
456     compareFiles(test_remotePathB, test_localPathB);
457 
458     ok(DeleteFileW(test_remotePathA), "DeleteFile\n");
459     ok(DeleteFileW(test_remotePathB), "DeleteFile\n");
460     DeleteFileW(test_localPathA);
461     DeleteFileW(test_localPathB);
462 
463     HeapFree(GetProcessHeap(), 0, urlA);
464     HeapFree(GetProcessHeap(), 0, urlB);
465 }
466 
467 static void test_NotifyFlags(void)
468 {
469     ULONG flags;
470     HRESULT hr;
471 
472     /* check default flags */
473     flags = 0;
474     hr = IBackgroundCopyJob_GetNotifyFlags(test_job, &flags);
475     ok(hr == S_OK, "got 0x%08x\n", hr);
476     ok(flags == (BG_NOTIFY_JOB_ERROR | BG_NOTIFY_JOB_TRANSFERRED), "flags 0x%08x\n", flags);
477 }
478 
479 static void test_NotifyInterface(void)
480 {
481     HRESULT hr;
482     IUnknown *unk;
483 
484     unk = (IUnknown*)0xdeadbeef;
485     hr = IBackgroundCopyJob_GetNotifyInterface(test_job, &unk);
486     ok(hr == S_OK, "got 0x%08x\n", hr);
487     ok(unk == NULL, "got %p\n", unk);
488 }
489 
490 static void test_Cancel(void)
491 {
492     HRESULT hr;
493     BG_JOB_STATE state;
494 
495     state = BG_JOB_STATE_ERROR;
496     hr = IBackgroundCopyJob_GetState(test_job, &state);
497     ok(hr == S_OK, "got 0x%08x\n", hr);
498     ok(state != BG_JOB_STATE_CANCELLED, "got %u\n", state);
499 
500     hr = IBackgroundCopyJob_Cancel(test_job);
501     ok(hr == S_OK, "got 0x%08x\n", hr);
502 
503     state = BG_JOB_STATE_ERROR;
504     hr = IBackgroundCopyJob_GetState(test_job, &state);
505     ok(hr == S_OK, "got 0x%08x\n", hr);
506     ok(state == BG_JOB_STATE_CANCELLED, "got %u\n", state);
507 
508     hr = IBackgroundCopyJob_Cancel(test_job);
509     ok(hr == BG_E_INVALID_STATE, "got 0x%08x\n", hr);
510 }
511 
512 static void test_HttpOptions(void)
513 {
514     static const WCHAR urlW[] =
515         {'h','t','t','p','s',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g','/',0};
516     static const WCHAR winetestW[] =
517         {'W','i','n','e',':',' ','t','e','s','t','\r','\n',0};
518     static const unsigned int timeout = 30;
519     HRESULT hr;
520     IBackgroundCopyJobHttpOptions *options;
521     IBackgroundCopyError *error;
522     BG_JOB_STATE state;
523     unsigned int i;
524     WCHAR *headers;
525     ULONG flags, orig_flags;
526 
527     DeleteFileW(test_localPathA);
528     hr = IBackgroundCopyJob_AddFile(test_job, urlW, test_localPathA);
529     ok(hr == S_OK, "got 0x%08x\n", hr);
530 
531     hr = IBackgroundCopyJob_QueryInterface(test_job, &IID_IBackgroundCopyJobHttpOptions, (void **)&options);
532     ok(hr == S_OK, "got 0x%08x\n", hr);
533 
534     if (options)
535     {
536         headers = (WCHAR *)0xdeadbeef;
537         hr = IBackgroundCopyJobHttpOptions_GetCustomHeaders(options, &headers);
538         ok(hr == S_FALSE, "got 0x%08x\n", hr);
539         ok(headers == NULL, "got %p\n", headers);
540 
541         hr = IBackgroundCopyJobHttpOptions_SetCustomHeaders(options, winetestW);
542         ok(hr == S_OK, "got 0x%08x\n", hr);
543 
544         headers = (WCHAR *)0xdeadbeef;
545         hr = IBackgroundCopyJobHttpOptions_GetCustomHeaders(options, &headers);
546         ok(hr == S_OK, "got 0x%08x\n", hr);
547         if (hr == S_OK)
548         {
549             ok(!lstrcmpW(headers, winetestW), "got %s\n", wine_dbgstr_w(headers));
550             CoTaskMemFree(headers);
551         }
552 
553         hr = IBackgroundCopyJobHttpOptions_SetCustomHeaders(options, NULL);
554         ok(hr == S_OK, "got 0x%08x\n", hr);
555 
556         headers = (WCHAR *)0xdeadbeef;
557         hr = IBackgroundCopyJobHttpOptions_GetCustomHeaders(options, &headers);
558         ok(hr == S_FALSE, "got 0x%08x\n", hr);
559         ok(headers == NULL, "got %p\n", headers);
560 
561         orig_flags = 0xdeadbeef;
562         hr = IBackgroundCopyJobHttpOptions_GetSecurityFlags(options, &orig_flags);
563         ok(hr == S_OK, "got 0x%08x\n", hr);
564         ok(!orig_flags, "got 0x%08x\n", orig_flags);
565 
566         hr = IBackgroundCopyJobHttpOptions_SetSecurityFlags(options, 0);
567         ok(hr == S_OK, "got 0x%08x\n", hr);
568 
569         flags = 0xdeadbeef;
570         hr = IBackgroundCopyJobHttpOptions_GetSecurityFlags(options, &flags);
571         ok(hr == S_OK, "got 0x%08x\n", hr);
572         ok(!flags, "got 0x%08x\n", flags);
573     }
574 
575     hr = IBackgroundCopyJob_Resume(test_job);
576     ok(hr == S_OK, "got 0x%08x\n", hr);
577 
578     for (i = 0; i < timeout; i++)
579     {
580         hr = IBackgroundCopyJob_GetState(test_job, &state);
581         ok(hr == S_OK, "got 0x%08x\n", hr);
582 
583         ok(state == BG_JOB_STATE_QUEUED ||
584            state == BG_JOB_STATE_CONNECTING ||
585            state == BG_JOB_STATE_TRANSFERRING ||
586            state == BG_JOB_STATE_TRANSFERRED, "unexpected state: %u\n", state);
587 
588         if (state == BG_JOB_STATE_TRANSFERRED) break;
589         Sleep(1000);
590     }
591     ok(i < timeout, "BITS job timed out\n");
592     if (i < timeout)
593     {
594         hr = IBackgroundCopyJob_GetError(test_job, &error);
595         ok(hr == BG_E_ERROR_INFORMATION_UNAVAILABLE, "got 0x%08x\n", hr);
596     }
597 
598     if (options)
599     {
600         headers = (WCHAR *)0xdeadbeef;
601         hr = IBackgroundCopyJobHttpOptions_GetCustomHeaders(options, &headers);
602         ok(hr == S_FALSE, "got 0x%08x\n", hr);
603         ok(headers == NULL, "got %p\n", headers);
604 
605         hr = IBackgroundCopyJobHttpOptions_SetCustomHeaders(options, NULL);
606         ok(hr == S_OK, "got 0x%08x\n", hr);
607 
608         hr = IBackgroundCopyJobHttpOptions_GetCustomHeaders(options, &headers);
609         ok(hr == S_FALSE, "got 0x%08x\n", hr);
610 
611         flags = 0xdeadbeef;
612         hr = IBackgroundCopyJobHttpOptions_GetSecurityFlags(options, &flags);
613         ok(hr == S_OK, "got 0x%08x\n", hr);
614         ok(!flags, "got 0x%08x\n", flags);
615 
616         hr = IBackgroundCopyJobHttpOptions_SetSecurityFlags(options, orig_flags);
617         ok(hr == S_OK, "got 0x%08x\n", hr);
618 
619         IBackgroundCopyJobHttpOptions_Release(options);
620     }
621 
622     hr = IBackgroundCopyJob_Complete(test_job);
623     ok(hr == S_OK, "got 0x%08x\n", hr);
624 
625     hr = IBackgroundCopyJob_GetState(test_job, &state);
626     ok(hr == S_OK, "got 0x%08x\n", hr);
627     ok(state == BG_JOB_STATE_ACKNOWLEDGED, "unexpected state: %u\n", state);
628 
629     hr = IBackgroundCopyJob_Complete(test_job);
630     ok(hr == BG_E_INVALID_STATE, "got 0x%08x\n", hr);
631 
632     DeleteFileW(test_localPathA);
633 }
634 
635 typedef void (*test_t)(void);
636 
637 START_TEST(job)
638 {
639     static const test_t tests[] = {
640         test_GetId,
641         test_GetType,
642         test_GetName,
643         test_GetProgress_preTransfer,
644         test_GetState,
645         test_ResumeEmpty,
646         test_NotifyFlags,
647         test_NotifyInterface,
648         0
649     };
650     static const test_t tests_bits20[] = {
651         test_AddFile,
652         test_AddFileSet,
653         test_EnumFiles,
654         test_CompleteLocal,
655         test_CompleteLocalURL,
656         test_Cancel, /* must be last */
657         0
658     };
659     static const test_t tests_bits25[] = {
660         test_HttpOptions,
661         0
662     };
663     const test_t *test;
664     int i;
665 
666     init_paths();
667 
668     CoInitialize(NULL);
669 
670     if (FAILED(test_create_manager()))
671     {
672         CoUninitialize();
673         win_skip("Failed to create Manager instance, skipping tests\n");
674         return;
675     }
676 
677     for (test = tests, i = 0; *test; ++test, ++i)
678     {
679         /* Keep state separate between tests. */
680         if (!setup())
681         {
682             ok(0, "tests:%d: Unable to setup test\n", i);
683             break;
684         }
685         (*test)();
686         teardown();
687     }
688 
689     if (check_bits20())
690     {
691         for (test = tests_bits20, i = 0; *test; ++test, ++i)
692         {
693             /* Keep state separate between tests. */
694             if (!setup())
695             {
696                 ok(0, "tests_bits20:%d: Unable to setup test\n", i);
697                 break;
698             }
699             (*test)();
700             teardown();
701         }
702     }
703     else
704     {
705         win_skip("Tests need BITS 2.0 or higher\n");
706     }
707 
708     if (check_bits25())
709     {
710         for (test = tests_bits25, i = 0; *test; ++test, ++i)
711         {
712             /* Keep state separate between tests. */
713             if (!setup())
714             {
715                 ok(0, "tests_bits25:%d: Unable to setup test\n", i);
716                 break;
717             }
718             (*test)();
719             teardown();
720         }
721     }
722     else
723     {
724         win_skip("Tests need BITS 2.5 or higher\n");
725     }
726 
727     CoUninitialize();
728 }
729