VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py@ 84175

Last change on this file since 84175 was 84175, checked in by vboxsync, 5 years ago

Validation Kit/tdAddGuestCtrl: Added facility testing of VBoxService by waiting for readiness before starting to test anything with it.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 245.5 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# pylint: disable=too-many-lines
4
5"""
6VirtualBox Validation Kit - Guest Control Tests.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2020 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 84175 $"
31
32# Standard Python imports.
33import errno
34import os
35import random
36import struct
37import sys
38import threading
39import time
40
41# Only the main script needs to modify the path.
42try: __file__
43except: __file__ = sys.argv[0];
44g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
45sys.path.append(g_ksValidationKitDir);
46
47# Validation Kit imports.
48from testdriver import reporter;
49from testdriver import base;
50from testdriver import testfileset;
51from testdriver import vbox;
52from testdriver import vboxcon;
53from testdriver import vboxtestfileset;
54from testdriver import vboxwrappers;
55from common import utils;
56
57# Python 3 hacks:
58if sys.version_info[0] >= 3:
59 long = int # pylint: disable=redefined-builtin,invalid-name
60 xrange = range; # pylint: disable=redefined-builtin,invalid-name
61
62
63class GuestStream(bytearray):
64 """
65 Class for handling a guest process input/output stream.
66
67 @todo write stdout/stderr tests.
68 """
69 def appendStream(self, stream, convertTo = '<b'):
70 """
71 Appends and converts a byte sequence to this object;
72 handy for displaying a guest stream.
73 """
74 self.extend(struct.pack(convertTo, stream));
75
76
77class tdCtxCreds(object):
78 """
79 Provides credentials to pass to the guest.
80 """
81 def __init__(self, sUser = None, sPassword = None, sDomain = None):
82 self.oTestVm = None;
83 self.sUser = sUser;
84 self.sPassword = sPassword;
85 self.sDomain = sDomain;
86
87 def applyDefaultsIfNotSet(self, oTestVm):
88 """
89 Applies credential defaults, based on the test VM (guest OS), if
90 no credentials were set yet.
91 """
92 self.oTestVm = oTestVm;
93 assert self.oTestVm is not None;
94
95 if self.sUser is None:
96 self.sUser = self.oTestVm.getTestUser();
97
98 if self.sPassword is None:
99 self.sPassword = self.oTestVm.getTestUserPassword(self.sUser);
100
101 if self.sDomain is None:
102 self.sDomain = '';
103
104class tdTestGuestCtrlBase(object):
105 """
106 Base class for all guest control tests.
107
108 Note: This test ASSUMES that working Guest Additions
109 were installed and running on the guest to be tested.
110 """
111 def __init__(self, oCreds = None):
112 self.oGuest = None; ##< IGuest.
113 self.oCreds = oCreds ##< type: tdCtxCreds
114 self.timeoutMS = 30 * 1000; ##< 30s timeout
115 self.oGuestSession = None; ##< IGuestSession reference or None.
116
117 def setEnvironment(self, oSession, oTxsSession, oTestVm):
118 """
119 Sets the test environment required for this test.
120 """
121 _ = oTxsSession;
122
123 try:
124 self.oGuest = oSession.o.console.guest;
125 except:
126 reporter.errorXcpt();
127
128 if self.oCreds is None:
129 self.oCreds = tdCtxCreds();
130 self.oCreds.applyDefaultsIfNotSet(oTestVm);
131
132 return True;
133
134 def uploadLogData(self, oTstDrv, aData, sFileName, sDesc):
135 """
136 Uploads (binary) data to a log file for manual (later) inspection.
137 """
138 reporter.log('Creating + uploading log data file "%s"' % sFileName);
139 sHstFileName = os.path.join(oTstDrv.sScratchPath, sFileName);
140 try:
141 oCurTestFile = open(sHstFileName, "wb");
142 oCurTestFile.write(aData);
143 oCurTestFile.close();
144 except:
145 return reporter.error('Unable to create temporary file for "%s"' % (sDesc,));
146 return reporter.addLogFile(sHstFileName, 'misc/other', sDesc);
147
148 def createSession(self, sName, fIsError = True):
149 """
150 Creates (opens) a guest session.
151 Returns (True, IGuestSession) on success or (False, None) on failure.
152 """
153 if self.oGuestSession is None:
154 if sName is None:
155 sName = "<untitled>";
156
157 reporter.log('Creating session "%s" ...' % (sName,));
158 try:
159 self.oGuestSession = self.oGuest.createSession(self.oCreds.sUser,
160 self.oCreds.sPassword,
161 self.oCreds.sDomain,
162 sName);
163 except:
164 # Just log, don't assume an error here (will be done in the main loop then).
165 reporter.maybeErrXcpt(fIsError, 'Creating a guest session "%s" failed; sUser="%s", pw="%s", sDomain="%s":'
166 % (sName, self.oCreds.sUser, self.oCreds.sPassword, self.oCreds.sDomain));
167 return (False, None);
168
169 reporter.log('Waiting for session "%s" to start within %dms...' % (sName, self.timeoutMS));
170 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
171 try:
172 waitResult = self.oGuestSession.waitForArray(aeWaitFor, self.timeoutMS);
173
174 #
175 # Be nice to Guest Additions < 4.3: They don't support session handling and
176 # therefore return WaitFlagNotSupported.
177 #
178 if waitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
179 # Just log, don't assume an error here (will be done in the main loop then).
180 reporter.maybeErr(fIsError, 'Session did not start successfully, returned wait result: %d' % (waitResult,));
181 return (False, None);
182 reporter.log('Session "%s" successfully started' % (sName,));
183 except:
184 # Just log, don't assume an error here (will be done in the main loop then).
185 reporter.maybeErrXcpt(fIsError, 'Waiting for guest session "%s" (usr=%s;pw=%s;dom=%s) to start failed:'
186 % (sName, self.oCreds.sUser, self.oCreds.sPassword, self.oCreds.sDomain,));
187 return (False, None);
188 else:
189 reporter.log('Warning: Session already set; this is probably not what you want');
190 return (True, self.oGuestSession);
191
192 def setSession(self, oGuestSession):
193 """
194 Sets the current guest session and closes
195 an old one if necessary.
196 """
197 if self.oGuestSession is not None:
198 self.closeSession();
199 self.oGuestSession = oGuestSession;
200 return self.oGuestSession;
201
202 def closeSession(self, fIsError = True):
203 """
204 Closes the guest session.
205 """
206 if self.oGuestSession is not None:
207 try:
208 sName = self.oGuestSession.name;
209 except:
210 return reporter.errorXcpt();
211
212 reporter.log('Closing session "%s" ...' % (sName,));
213 try:
214 self.oGuestSession.close();
215 self.oGuestSession = None;
216 except:
217 # Just log, don't assume an error here (will be done in the main loop then).
218 reporter.maybeErrXcpt(fIsError, 'Closing guest session "%s" failed:' % (sName,));
219 return False;
220 return True;
221
222class tdTestCopyFrom(tdTestGuestCtrlBase):
223 """
224 Test for copying files from the guest to the host.
225 """
226 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None, oSrc = None):
227 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
228 self.sSrc = sSrc;
229 self.sDst = sDst;
230 self.afFlags = afFlags;
231 self.oSrc = oSrc # type: testfileset.TestFsObj
232 if oSrc and not sSrc:
233 self.sSrc = oSrc.sPath;
234
235class tdTestCopyFromDir(tdTestCopyFrom):
236
237 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None, oSrc = None, fIntoDst = False):
238 tdTestCopyFrom.__init__(self, sSrc, sDst, oCreds, afFlags, oSrc);
239 self.fIntoDst = fIntoDst; # hint to the verification code that sDst == oSrc, rather than sDst+oSrc.sNAme == oSrc.
240
241class tdTestCopyFromFile(tdTestCopyFrom):
242 pass;
243
244class tdTestRemoveHostDir(object):
245 """
246 Test step that removes a host directory tree.
247 """
248 def __init__(self, sDir):
249 self.sDir = sDir;
250
251 def execute(self, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
252 _ = oTstDrv; _ = oVmSession; _ = oTxsSession; _ = oTestVm; _ = sMsgPrefix;
253 if os.path.exists(self.sDir):
254 if base.wipeDirectory(self.sDir) != 0:
255 return False;
256 try:
257 os.rmdir(self.sDir);
258 except:
259 return reporter.errorXcpt('%s: sDir=%s' % (sMsgPrefix, self.sDir,));
260 return True;
261
262
263
264class tdTestCopyTo(tdTestGuestCtrlBase):
265 """
266 Test for copying files from the host to the guest.
267 """
268 def __init__(self, sSrc = "", sDst = "", oCreds = None, afFlags = None):
269 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
270 self.sSrc = sSrc;
271 self.sDst = sDst;
272 self.afFlags = afFlags;
273
274class tdTestCopyToFile(tdTestCopyTo):
275 pass;
276
277class tdTestCopyToDir(tdTestCopyTo):
278 pass;
279
280class tdTestDirCreate(tdTestGuestCtrlBase):
281 """
282 Test for directoryCreate call.
283 """
284 def __init__(self, sDirectory = "", oCreds = None, fMode = 0, afFlags = None):
285 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
286 self.sDirectory = sDirectory;
287 self.fMode = fMode;
288 self.afFlags = afFlags;
289
290class tdTestDirCreateTemp(tdTestGuestCtrlBase):
291 """
292 Test for the directoryCreateTemp call.
293 """
294 def __init__(self, sDirectory = "", sTemplate = "", oCreds = None, fMode = 0, fSecure = False):
295 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
296 self.sDirectory = sDirectory;
297 self.sTemplate = sTemplate;
298 self.fMode = fMode;
299 self.fSecure = fSecure;
300
301class tdTestDirOpen(tdTestGuestCtrlBase):
302 """
303 Test for the directoryOpen call.
304 """
305 def __init__(self, sDirectory = "", oCreds = None, sFilter = "", afFlags = None):
306 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
307 self.sDirectory = sDirectory;
308 self.sFilter = sFilter;
309 self.afFlags = afFlags or [];
310
311class tdTestDirRead(tdTestDirOpen):
312 """
313 Test for the opening, reading and closing a certain directory.
314 """
315 def __init__(self, sDirectory = "", oCreds = None, sFilter = "", afFlags = None):
316 tdTestDirOpen.__init__(self, sDirectory, oCreds, sFilter, afFlags);
317
318class tdTestExec(tdTestGuestCtrlBase):
319 """
320 Specifies exactly one guest control execution test.
321 Has a default timeout of 5 minutes (for safety).
322 """
323 def __init__(self, sCmd = "", asArgs = None, aEnv = None, afFlags = None, # pylint: disable=too-many-arguments
324 timeoutMS = 5 * 60 * 1000, oCreds = None, fWaitForExit = True):
325 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
326 self.sCmd = sCmd;
327 self.asArgs = asArgs if asArgs is not None else [sCmd,];
328 self.aEnv = aEnv;
329 self.afFlags = afFlags or [];
330 self.timeoutMS = timeoutMS;
331 self.fWaitForExit = fWaitForExit;
332 self.uExitStatus = 0;
333 self.iExitCode = 0;
334 self.cbStdOut = 0;
335 self.cbStdErr = 0;
336 self.sBuf = '';
337
338class tdTestFileExists(tdTestGuestCtrlBase):
339 """
340 Test for the file exists API call (fileExists).
341 """
342 def __init__(self, sFile = "", oCreds = None):
343 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
344 self.sFile = sFile;
345
346class tdTestFileRemove(tdTestGuestCtrlBase):
347 """
348 Test querying guest file information.
349 """
350 def __init__(self, sFile = "", oCreds = None):
351 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
352 self.sFile = sFile;
353
354class tdTestRemoveBase(tdTestGuestCtrlBase):
355 """
356 Removal base.
357 """
358 def __init__(self, sPath, fRcExpect = True, oCreds = None):
359 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
360 self.sPath = sPath;
361 self.fRcExpect = fRcExpect;
362
363 def execute(self, oSubTstDrv):
364 """
365 Executes the test, returns True/False.
366 """
367 _ = oSubTstDrv;
368 return True;
369
370 def checkRemoved(self, sType):
371 """ Check that the object was removed using fObjExists. """
372 try:
373 fExists = self.oGuestSession.fsObjExists(self.sPath, False);
374 except:
375 return reporter.errorXcpt('fsObjExists failed on "%s" after deletion (type: %s)' % (self.sPath, sType));
376 if fExists:
377 return reporter.error('fsObjExists says "%s" still exists after deletion (type: %s)!' % (self.sPath, sType));
378 return True;
379
380class tdTestRemoveFile(tdTestRemoveBase):
381 """
382 Remove a single file.
383 """
384 def __init__(self, sPath, fRcExpect = True, oCreds = None):
385 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds);
386
387 def execute(self, oSubTstDrv):
388 reporter.log2('Deleting file "%s" ...' % (self.sPath,));
389 try:
390 if oSubTstDrv.oTstDrv.fpApiVer >= 5.0:
391 self.oGuestSession.fsObjRemove(self.sPath);
392 else:
393 self.oGuestSession.fileRemove(self.sPath);
394 except:
395 reporter.maybeErrXcpt(self.fRcExpect, 'Removing "%s" failed' % (self.sPath,));
396 return not self.fRcExpect;
397 if not self.fRcExpect:
398 return reporter.error('Expected removing "%s" to failed, but it succeeded' % (self.sPath,));
399
400 return self.checkRemoved('file');
401
402class tdTestRemoveDir(tdTestRemoveBase):
403 """
404 Remove a single directory if empty.
405 """
406 def __init__(self, sPath, fRcExpect = True, oCreds = None):
407 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds);
408
409 def execute(self, oSubTstDrv):
410 _ = oSubTstDrv;
411 reporter.log2('Deleting directory "%s" ...' % (self.sPath,));
412 try:
413 self.oGuestSession.directoryRemove(self.sPath);
414 except:
415 reporter.maybeErrXcpt(self.fRcExpect, 'Removing "%s" (as a directory) failed' % (self.sPath,));
416 return not self.fRcExpect;
417 if not self.fRcExpect:
418 return reporter.error('Expected removing "%s" (dir) to failed, but it succeeded' % (self.sPath,));
419
420 return self.checkRemoved('directory');
421
422class tdTestRemoveTree(tdTestRemoveBase):
423 """
424 Recursively remove a directory tree.
425 """
426 def __init__(self, sPath, afFlags = None, fRcExpect = True, fNotExist = False, oCreds = None):
427 tdTestRemoveBase.__init__(self, sPath, fRcExpect, oCreds = None);
428 self.afFlags = afFlags if afFlags is not None else [];
429 self.fNotExist = fNotExist; # Hack for the ContentOnly scenario where the dir does not exist.
430
431 def execute(self, oSubTstDrv):
432 reporter.log2('Deleting tree "%s" ...' % (self.sPath,));
433 try:
434 oProgress = self.oGuestSession.directoryRemoveRecursive(self.sPath, self.afFlags);
435 except:
436 reporter.maybeErrXcpt(self.fRcExpect, 'Removing directory tree "%s" failed (afFlags=%s)'
437 % (self.sPath, self.afFlags));
438 return not self.fRcExpect;
439
440 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, oSubTstDrv.oTstDrv.oVBoxMgr, oSubTstDrv.oTstDrv,
441 "remove-tree: %s" % (self.sPath,));
442 oWrappedProgress.wait();
443 if not oWrappedProgress.isSuccess():
444 oWrappedProgress.logResult(fIgnoreErrors = not self.fRcExpect);
445 return not self.fRcExpect;
446 if not self.fRcExpect:
447 return reporter.error('Expected removing "%s" (tree) to failed, but it succeeded' % (self.sPath,));
448
449 if vboxcon.DirectoryRemoveRecFlag_ContentAndDir not in self.afFlags and not self.fNotExist:
450 # Cannot use directoryExists here as it is buggy.
451 try:
452 if oSubTstDrv.oTstDrv.fpApiVer >= 5.0:
453 oFsObjInfo = self.oGuestSession.fsObjQueryInfo(self.sPath, False);
454 else:
455 oFsObjInfo = self.oGuestSession.fileQueryInfo(self.sPath);
456 eType = oFsObjInfo.type;
457 except:
458 return reporter.errorXcpt('sPath=%s' % (self.sPath,));
459 if eType != vboxcon.FsObjType_Directory:
460 return reporter.error('Found file type %d, expected directory (%d) for %s after rmtree/OnlyContent'
461 % (eType, vboxcon.FsObjType_Directory, self.sPath,));
462 return True;
463
464 return self.checkRemoved('tree');
465
466
467class tdTestFileStat(tdTestGuestCtrlBase):
468 """
469 Test querying guest file information.
470 """
471 def __init__(self, sFile = "", oCreds = None, cbSize = 0, eFileType = 0):
472 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
473 self.sFile = sFile;
474 self.cbSize = cbSize;
475 self.eFileType = eFileType;
476
477class tdTestFileIO(tdTestGuestCtrlBase):
478 """
479 Test for the IGuestFile object.
480 """
481 def __init__(self, sFile = "", oCreds = None):
482 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
483 self.sFile = sFile;
484
485class tdTestFileQuerySize(tdTestGuestCtrlBase):
486 """
487 Test for the file size query API call (fileQuerySize).
488 """
489 def __init__(self, sFile = "", oCreds = None):
490 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
491 self.sFile = sFile;
492
493class tdTestFileOpen(tdTestGuestCtrlBase):
494 """
495 Tests opening a guest files.
496 """
497 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None,
498 fCreationMode = 0o660, oCreds = None):
499 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
500 self.sFile = sFile;
501 self.eAccessMode = eAccessMode if eAccessMode is not None else vboxcon.FileAccessMode_ReadOnly;
502 self.eAction = eAction if eAction is not None else vboxcon.FileOpenAction_OpenExisting;
503 self.eSharing = eSharing if eSharing is not None else vboxcon.FileSharingMode_All;
504 self.fCreationMode = fCreationMode;
505 self.afOpenFlags = [];
506 self.oOpenedFile = None;
507
508 def toString(self):
509 """ Get a summary string. """
510 return 'eAccessMode=%s eAction=%s sFile=%s' % (self.eAccessMode, self.eAction, self.sFile);
511
512 def doOpenStep(self, fExpectSuccess):
513 """
514 Does the open step, putting the resulting file in oOpenedFile.
515 """
516 try:
517 self.oOpenedFile = self.oGuestSession.fileOpenEx(self.sFile, self.eAccessMode, self.eAction,
518 self.eSharing, self.fCreationMode, self.afOpenFlags);
519 except:
520 reporter.maybeErrXcpt(fExpectSuccess, 'fileOpenEx(%s, %s, %s, %s, %s, %s)'
521 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
522 self.fCreationMode, self.afOpenFlags,));
523 return False;
524 return True;
525
526 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
527 """ Overridden by children to do more testing. """
528 _ = fExpectSuccess; _ = oSubTst;
529 return True;
530
531 def doCloseStep(self):
532 """ Closes the file. """
533 if self.oOpenedFile:
534 try:
535 self.oOpenedFile.close();
536 except:
537 return reporter.errorXcpt('close([%s, %s, %s, %s, %s, %s])'
538 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
539 self.fCreationMode, self.afOpenFlags,));
540 self.oOpenedFile = None;
541 return True;
542
543 def doSteps(self, fExpectSuccess, oSubTst):
544 """ Do the tests. """
545 fRc = self.doOpenStep(fExpectSuccess);
546 if fRc is True:
547 fRc = self.doStepsOnOpenedFile(fExpectSuccess, oSubTst);
548 if self.oOpenedFile:
549 fRc = self.doCloseStep() and fRc;
550 return fRc;
551
552
553class tdTestFileOpenCheckSize(tdTestFileOpen):
554 """
555 Opens a file and checks the size.
556 """
557 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None,
558 fCreationMode = 0o660, cbOpenExpected = 0, oCreds = None):
559 tdTestFileOpen.__init__(self, sFile, eAccessMode, eAction, eSharing, fCreationMode, oCreds);
560 self.cbOpenExpected = cbOpenExpected;
561
562 def toString(self):
563 return 'cbOpenExpected=%s %s' % (self.cbOpenExpected, tdTestFileOpen.toString(self),);
564
565 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
566 #
567 # Call parent.
568 #
569 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
570
571 #
572 # Check the size. Requires 6.0 or later (E_NOTIMPL in 5.2).
573 #
574 if oSubTst.oTstDrv.fpApiVer >= 6.0:
575 try:
576 oFsObjInfo = self.oOpenedFile.queryInfo();
577 except:
578 return reporter.errorXcpt('queryInfo([%s, %s, %s, %s, %s, %s])'
579 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
580 self.fCreationMode, self.afOpenFlags,));
581 if oFsObjInfo is None:
582 return reporter.error('IGuestFile::queryInfo returned None');
583 try:
584 cbFile = oFsObjInfo.objectSize;
585 except:
586 return reporter.errorXcpt();
587 if cbFile != self.cbOpenExpected:
588 return reporter.error('Wrong file size after open (%d): %s, expected %s (file %s) (#1)'
589 % (self.eAction, cbFile, self.cbOpenExpected, self.sFile));
590
591 try:
592 cbFile = self.oOpenedFile.querySize();
593 except:
594 return reporter.errorXcpt('querySize([%s, %s, %s, %s, %s, %s])'
595 % (self.sFile, self.eAccessMode, self.eAction, self.eSharing,
596 self.fCreationMode, self.afOpenFlags,));
597 if cbFile != self.cbOpenExpected:
598 return reporter.error('Wrong file size after open (%d): %s, expected %s (file %s) (#2)'
599 % (self.eAction, cbFile, self.cbOpenExpected, self.sFile));
600
601 return fRc;
602
603
604class tdTestFileOpenAndWrite(tdTestFileOpen):
605 """
606 Opens the file and writes one or more chunks to it.
607
608 The chunks are a list of tuples(offset, bytes), where offset can be None
609 if no seeking should be performed.
610 """
611 def __init__(self, sFile = "", eAccessMode = None, eAction = None, eSharing = None, # pylint: disable=too-many-arguments
612 fCreationMode = 0o660, atChunks = None, fUseAtApi = False, abContent = None, oCreds = None):
613 tdTestFileOpen.__init__(self, sFile, eAccessMode if eAccessMode is not None else vboxcon.FileAccessMode_WriteOnly,
614 eAction, eSharing, fCreationMode, oCreds);
615 assert atChunks is not None;
616 self.atChunks = atChunks # type: list(tuple(int,bytearray))
617 self.fUseAtApi = fUseAtApi;
618 self.fAppend = ( eAccessMode in (vboxcon.FileAccessMode_AppendOnly, vboxcon.FileAccessMode_AppendRead)
619 or eAction == vboxcon.FileOpenAction_AppendOrCreate);
620 self.abContent = abContent # type: bytearray
621
622 def toString(self):
623 sChunks = ', '.join('%s LB %s' % (tChunk[0], len(tChunk[1]),) for tChunk in self.atChunks);
624 sApi = 'writeAt' if self.fUseAtApi else 'write';
625 return '%s [%s] %s' % (sApi, sChunks, tdTestFileOpen.toString(self),);
626
627 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
628 #
629 # Call parent.
630 #
631 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
632
633 #
634 # Do the writing.
635 #
636 for offFile, abBuf in self.atChunks:
637 if self.fUseAtApi:
638 #
639 # writeAt:
640 #
641 assert offFile is not None;
642 reporter.log2('writeAt(%s, %s bytes)' % (offFile, len(abBuf),));
643 if self.fAppend:
644 if self.abContent is not None: # Try avoid seek as it updates the cached offset in GuestFileImpl.
645 offExpectAfter = len(self.abContent);
646 else:
647 try:
648 offSave = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
649 offExpectAfter = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_End);
650 self.oOpenedFile.seek(offSave, vboxcon.FileSeekOrigin_Begin);
651 except:
652 return reporter.errorXcpt();
653 offExpectAfter += len(abBuf);
654 else:
655 offExpectAfter = offFile + len(abBuf);
656
657 try:
658 cbWritten = self.oOpenedFile.writeAt(offFile, abBuf, 30*1000);
659 except:
660 return reporter.errorXcpt('writeAt(%s, %s bytes)' % (offFile, len(abBuf),));
661
662 else:
663 #
664 # write:
665 #
666 if self.fAppend:
667 if self.abContent is not None: # Try avoid seek as it updates the cached offset in GuestFileImpl.
668 offExpectAfter = len(self.abContent);
669 else:
670 try:
671 offSave = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
672 offExpectAfter = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_End);
673 self.oOpenedFile.seek(offSave, vboxcon.FileSeekOrigin_Begin);
674 except:
675 return reporter.errorXcpt('seek(0,End)');
676 if offFile is not None:
677 try:
678 self.oOpenedFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
679 except:
680 return reporter.errorXcpt('seek(%s,Begin)' % (offFile,));
681 else:
682 try:
683 offFile = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
684 except:
685 return reporter.errorXcpt();
686 if not self.fAppend:
687 offExpectAfter = offFile;
688 offExpectAfter += len(abBuf);
689
690 reporter.log2('write(%s bytes @ %s)' % (len(abBuf), offFile,));
691 try:
692 cbWritten = self.oOpenedFile.write(abBuf, 30*1000);
693 except:
694 return reporter.errorXcpt('write(%s bytes @ %s)' % (len(abBuf), offFile));
695
696 #
697 # Check how much was written, ASSUMING nothing we push thru here is too big:
698 #
699 if cbWritten != len(abBuf):
700 fRc = reporter.errorXcpt('Wrote less than expected: %s out of %s, expected all to be written'
701 % (cbWritten, len(abBuf),));
702 if not self.fAppend:
703 offExpectAfter -= len(abBuf) - cbWritten;
704
705 #
706 # Update the file content tracker if we've got one and can:
707 #
708 if self.abContent is not None:
709 if cbWritten < len(abBuf):
710 abBuf = abBuf[:cbWritten];
711
712 #
713 # In append mode, the current file offset shall be disregarded and the
714 # write always goes to the end of the file, regardless of writeAt or write.
715 # Note that RTFileWriteAt only naturally behaves this way on linux and
716 # (probably) windows, so VBoxService makes that behaviour generic across
717 # all OSes.
718 #
719 if self.fAppend:
720 reporter.log2('len(self.abContent)=%s + %s' % (len(self.abContent), cbWritten, ));
721 self.abContent.extend(abBuf);
722 else:
723 if offFile is None:
724 offFile = offExpectAfter - cbWritten;
725 reporter.log2('len(self.abContent)=%s + %s @ %s' % (len(self.abContent), cbWritten, offFile, ));
726 if offFile > len(self.abContent):
727 self.abContent.extend(bytearray(offFile - len(self.abContent)));
728 self.abContent[offFile:offFile + cbWritten] = abBuf;
729 reporter.log2('len(self.abContent)=%s' % (len(self.abContent),));
730
731 #
732 # Check the resulting file offset with IGuestFile::offset.
733 #
734 try:
735 offApi = self.oOpenedFile.offset; # Must be gotten first!
736 offSeek = self.oOpenedFile.seek(0, vboxcon.FileSeekOrigin_Current);
737 except:
738 fRc = reporter.errorXcpt();
739 else:
740 reporter.log2('offApi=%s offSeek=%s offExpectAfter=%s' % (offApi, offSeek, offExpectAfter,));
741 if offSeek != offExpectAfter:
742 fRc = reporter.error('Seek offset is %s, expected %s after %s bytes write @ %s (offApi=%s)'
743 % (offSeek, offExpectAfter, len(abBuf), offFile, offApi,));
744 if offApi != offExpectAfter:
745 fRc = reporter.error('IGuestFile::offset is %s, expected %s after %s bytes write @ %s (offSeek=%s)'
746 % (offApi, offExpectAfter, len(abBuf), offFile, offSeek,));
747 # for each chunk - end
748 return fRc;
749
750
751class tdTestFileOpenAndCheckContent(tdTestFileOpen):
752 """
753 Opens the file and checks the content using the read API.
754 """
755 def __init__(self, sFile = "", eSharing = None, abContent = None, cbContentExpected = None, oCreds = None):
756 tdTestFileOpen.__init__(self, sFile = sFile, eSharing = eSharing, oCreds = oCreds);
757 self.abContent = abContent # type: bytearray
758 self.cbContentExpected = cbContentExpected;
759
760 def toString(self):
761 return 'check content %s (%s) %s' % (len(self.abContent), self.cbContentExpected, tdTestFileOpen.toString(self),);
762
763 def doStepsOnOpenedFile(self, fExpectSuccess, oSubTst):
764 #
765 # Call parent.
766 #
767 fRc = tdTestFileOpen.doStepsOnOpenedFile(self, fExpectSuccess, oSubTst);
768
769 #
770 # Check the expected content size.
771 #
772 if self.cbContentExpected is not None:
773 if len(self.abContent) != self.cbContentExpected:
774 fRc = reporter.error('Incorrect abContent size: %s, expected %s'
775 % (len(self.abContent), self.cbContentExpected,));
776
777 #
778 # Read the file and compare it with the content.
779 #
780 offFile = 0;
781 while True:
782 try:
783 abChunk = self.oOpenedFile.read(512*1024, 30*1000);
784 except:
785 return reporter.errorXcpt('read(512KB) @ %s' % (offFile,));
786 cbChunk = len(abChunk);
787 if cbChunk == 0:
788 if offFile != len(self.abContent):
789 fRc = reporter.error('Unexpected EOF @ %s, len(abContent)=%s' % (offFile, len(self.abContent),));
790 break;
791 if offFile + cbChunk > len(self.abContent):
792 fRc = reporter.error('File is larger than expected: at least %s bytes, expected %s bytes'
793 % (offFile + cbChunk, len(self.abContent),));
794 elif not utils.areBytesEqual(abChunk, self.abContent[offFile:(offFile + cbChunk)]):
795 fRc = reporter.error('Mismatch in range %s LB %s!' % (offFile, cbChunk,));
796 offFile += cbChunk;
797
798 return fRc;
799
800
801class tdTestSession(tdTestGuestCtrlBase):
802 """
803 Test the guest session handling.
804 """
805 def __init__(self, sUser = None, sPassword = None, sDomain = None, sSessionName = ""):
806 tdTestGuestCtrlBase.__init__(self, oCreds = tdCtxCreds(sUser, sPassword, sDomain));
807 self.sSessionName = sSessionName;
808
809 def getSessionCount(self, oVBoxMgr):
810 """
811 Helper for returning the number of currently
812 opened guest sessions of a VM.
813 """
814 if self.oGuest is None:
815 return 0;
816 try:
817 aoSession = oVBoxMgr.getArray(self.oGuest, 'sessions')
818 except:
819 reporter.errorXcpt('sSessionName: %s' % (self.sSessionName,));
820 return 0;
821 return len(aoSession);
822
823
824class tdTestSessionEx(tdTestGuestCtrlBase):
825 """
826 Test the guest session.
827 """
828 def __init__(self, aoSteps = None, enmUser = None):
829 tdTestGuestCtrlBase.__init__(self);
830 assert enmUser is None; # For later.
831 self.enmUser = enmUser;
832 self.aoSteps = aoSteps if aoSteps is not None else [];
833
834 def execute(self, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
835 """
836 Executes the test.
837 """
838 #
839 # Create a session.
840 #
841 assert self.enmUser is None; # For later.
842 self.oCreds = tdCtxCreds();
843 self.setEnvironment(oVmSession, oTxsSession, oTestVm);
844 reporter.log2('%s: %s steps' % (sMsgPrefix, len(self.aoSteps),));
845 fRc, oCurSession = self.createSession(sMsgPrefix);
846 if fRc is True:
847 #
848 # Execute the tests.
849 #
850 try:
851 fRc = self.executeSteps(oTstDrv, oCurSession, sMsgPrefix);
852 except:
853 fRc = reporter.errorXcpt('%s: Unexpected exception executing test steps' % (sMsgPrefix,));
854
855 #
856 # Close the session.
857 #
858 fRc2 = self.closeSession();
859 if fRc2 is False:
860 fRc = reporter.error('%s: Session could not be closed' % (sMsgPrefix,));
861 else:
862 fRc = reporter.error('%s: Session creation failed' % (sMsgPrefix,));
863 return fRc;
864
865 def executeSteps(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
866 """
867 Executes just the steps.
868 Returns True on success, False on test failure.
869 """
870 fRc = True;
871 for (i, oStep) in enumerate(self.aoSteps):
872 fRc2 = oStep.execute(oTstDrv, oGstCtrlSession, sMsgPrefix + ', step #%d' % i);
873 if fRc2 is True:
874 pass;
875 elif fRc2 is None:
876 reporter.log('%s: skipping remaining %d steps' % (sMsgPrefix, len(self.aoSteps) - i - 1,));
877 break;
878 else:
879 fRc = False;
880 return fRc;
881
882 @staticmethod
883 def executeListTestSessions(aoTests, oTstDrv, oVmSession, oTxsSession, oTestVm, sMsgPrefix):
884 """
885 Works thru a list of tdTestSessionEx object.
886 """
887 fRc = True;
888 for (i, oCurTest) in enumerate(aoTests):
889 try:
890 fRc2 = oCurTest.execute(oTstDrv, oVmSession, oTxsSession, oTestVm, '%s / %#d' % (sMsgPrefix, i,));
891 if fRc2 is not True:
892 fRc = False;
893 except:
894 fRc = reporter.errorXcpt('%s: Unexpected exception executing test #%d' % (sMsgPrefix, i ,));
895
896 return (fRc, oTxsSession);
897
898
899class tdSessionStepBase(object):
900 """
901 Base class for the guest control session test steps.
902 """
903
904 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
905 """
906 Executes the test step.
907
908 Returns True on success.
909 Returns False on failure (must be reported as error).
910 Returns None if to skip the remaining steps.
911 """
912 _ = oTstDrv;
913 _ = oGstCtrlSession;
914 return reporter.error('%s: Missing execute implementation: %s' % (sMsgPrefix, self,));
915
916
917class tdStepRequireMinimumApiVer(tdSessionStepBase):
918 """
919 Special test step which will cause executeSteps to skip the remaining step
920 if the VBox API is too old:
921 """
922 def __init__(self, fpMinApiVer):
923 self.fpMinApiVer = fpMinApiVer;
924
925 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
926 """ Returns None if API version is too old, otherwise True. """
927 if oTstDrv.fpApiVer >= self.fpMinApiVer:
928 return True;
929 _ = oGstCtrlSession;
930 _ = sMsgPrefix;
931 return None; # Special return value. Don't use elsewhere.
932
933
934#
935# Scheduling Environment Changes with the Guest Control Session.
936#
937
938class tdStepSessionSetEnv(tdSessionStepBase):
939 """
940 Guest session environment: schedule putenv
941 """
942 def __init__(self, sVar, sValue, hrcExpected = 0):
943 self.sVar = sVar;
944 self.sValue = sValue;
945 self.hrcExpected = hrcExpected;
946
947 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
948 """
949 Executes the step.
950 Returns True on success, False on test failure.
951 """
952 reporter.log2('tdStepSessionSetEnv: sVar=%s sValue=%s hrcExpected=%#x' % (self.sVar, self.sValue, self.hrcExpected,));
953 try:
954 if oTstDrv.fpApiVer >= 5.0:
955 oGstCtrlSession.environmentScheduleSet(self.sVar, self.sValue);
956 else:
957 oGstCtrlSession.environmentSet(self.sVar, self.sValue);
958 except vbox.ComException as oXcpt:
959 # Is this an expected failure?
960 if vbox.ComError.equal(oXcpt, self.hrcExpected):
961 return True;
962 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (setenv %s=%s)'
963 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
964 vbox.ComError.getXcptResult(oXcpt),
965 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
966 self.sVar, self.sValue,));
967 except:
968 return reporter.errorXcpt('%s: Unexpected exception in tdStepSessionSetEnv::execute (%s=%s)'
969 % (sMsgPrefix, self.sVar, self.sValue,));
970
971 # Should we succeed?
972 if self.hrcExpected != 0:
973 return reporter.error('%s: Expected hrcExpected=%#x, got S_OK (putenv %s=%s)'
974 % (sMsgPrefix, self.hrcExpected, self.sVar, self.sValue,));
975 return True;
976
977class tdStepSessionUnsetEnv(tdSessionStepBase):
978 """
979 Guest session environment: schedule unset.
980 """
981 def __init__(self, sVar, hrcExpected = 0):
982 self.sVar = sVar;
983 self.hrcExpected = hrcExpected;
984
985 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
986 """
987 Executes the step.
988 Returns True on success, False on test failure.
989 """
990 reporter.log2('tdStepSessionUnsetEnv: sVar=%s hrcExpected=%#x' % (self.sVar, self.hrcExpected,));
991 try:
992 if oTstDrv.fpApiVer >= 5.0:
993 oGstCtrlSession.environmentScheduleUnset(self.sVar);
994 else:
995 oGstCtrlSession.environmentUnset(self.sVar);
996 except vbox.ComException as oXcpt:
997 # Is this an expected failure?
998 if vbox.ComError.equal(oXcpt, self.hrcExpected):
999 return True;
1000 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (unsetenv %s)'
1001 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
1002 vbox.ComError.getXcptResult(oXcpt),
1003 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
1004 self.sVar,));
1005 except:
1006 return reporter.errorXcpt('%s: Unexpected exception in tdStepSessionUnsetEnv::execute (%s)'
1007 % (sMsgPrefix, self.sVar,));
1008
1009 # Should we succeed?
1010 if self.hrcExpected != 0:
1011 return reporter.error('%s: Expected hrcExpected=%#x, got S_OK (unsetenv %s)'
1012 % (sMsgPrefix, self.hrcExpected, self.sVar,));
1013 return True;
1014
1015class tdStepSessionBulkEnv(tdSessionStepBase):
1016 """
1017 Guest session environment: Bulk environment changes.
1018 """
1019 def __init__(self, asEnv = None, hrcExpected = 0):
1020 self.asEnv = asEnv if asEnv is not None else [];
1021 self.hrcExpected = hrcExpected;
1022
1023 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1024 """
1025 Executes the step.
1026 Returns True on success, False on test failure.
1027 """
1028 reporter.log2('tdStepSessionBulkEnv: asEnv=%s hrcExpected=%#x' % (self.asEnv, self.hrcExpected,));
1029 try:
1030 if oTstDrv.fpApiVer >= 5.0:
1031 oTstDrv.oVBoxMgr.setArray(oGstCtrlSession, 'environmentChanges', self.asEnv);
1032 else:
1033 oTstDrv.oVBoxMgr.setArray(oGstCtrlSession, 'environment', self.asEnv);
1034 except vbox.ComException as oXcpt:
1035 # Is this an expected failure?
1036 if vbox.ComError.equal(oXcpt, self.hrcExpected):
1037 return True;
1038 return reporter.errorXcpt('%s: Expected hrc=%#x (%s) got %#x (%s) instead (asEnv=%s)'
1039 % (sMsgPrefix, self.hrcExpected, vbox.ComError.toString(self.hrcExpected),
1040 vbox.ComError.getXcptResult(oXcpt),
1041 vbox.ComError.toString(vbox.ComError.getXcptResult(oXcpt)),
1042 self.asEnv,));
1043 except:
1044 return reporter.errorXcpt('%s: Unexpected exception writing the environmentChanges property (asEnv=%s).'
1045 % (sMsgPrefix, self.asEnv));
1046 return True;
1047
1048class tdStepSessionClearEnv(tdStepSessionBulkEnv):
1049 """
1050 Guest session environment: clears the scheduled environment changes.
1051 """
1052 def __init__(self):
1053 tdStepSessionBulkEnv.__init__(self);
1054
1055
1056class tdStepSessionCheckEnv(tdSessionStepBase):
1057 """
1058 Check the currently scheduled environment changes of a guest control session.
1059 """
1060 def __init__(self, asEnv = None):
1061 self.asEnv = asEnv if asEnv is not None else [];
1062
1063 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1064 """
1065 Executes the step.
1066 Returns True on success, False on test failure.
1067 """
1068 reporter.log2('tdStepSessionCheckEnv: asEnv=%s' % (self.asEnv,));
1069
1070 #
1071 # Get the environment change list.
1072 #
1073 try:
1074 if oTstDrv.fpApiVer >= 5.0:
1075 asCurEnv = oTstDrv.oVBoxMgr.getArray(oGstCtrlSession, 'environmentChanges');
1076 else:
1077 asCurEnv = oTstDrv.oVBoxMgr.getArray(oGstCtrlSession, 'environment');
1078 except:
1079 return reporter.errorXcpt('%s: Unexpected exception reading the environmentChanges property.' % (sMsgPrefix,));
1080
1081 #
1082 # Compare it with the expected one by trying to remove each expected value
1083 # and the list anything unexpected.
1084 #
1085 fRc = True;
1086 asCopy = list(asCurEnv); # just in case asCurEnv is immutable
1087 for sExpected in self.asEnv:
1088 try:
1089 asCopy.remove(sExpected);
1090 except:
1091 fRc = reporter.error('%s: Expected "%s" to be in the resulting environment' % (sMsgPrefix, sExpected,));
1092 for sUnexpected in asCopy:
1093 fRc = reporter.error('%s: Unexpected "%s" in the resulting environment' % (sMsgPrefix, sUnexpected,));
1094
1095 if fRc is not True:
1096 reporter.log2('%s: Current environment: %s' % (sMsgPrefix, asCurEnv));
1097 return fRc;
1098
1099
1100#
1101# File system object statistics (i.e. stat()).
1102#
1103
1104class tdStepStat(tdSessionStepBase):
1105 """
1106 Stats a file system object.
1107 """
1108 def __init__(self, sPath, hrcExpected = 0, fFound = True, fFollowLinks = True, enmType = None, oTestFsObj = None):
1109 self.sPath = sPath;
1110 self.hrcExpected = hrcExpected;
1111 self.fFound = fFound;
1112 self.fFollowLinks = fFollowLinks;
1113 self.enmType = enmType if enmType is not None else vboxcon.FsObjType_File;
1114 self.cbExactSize = None;
1115 self.cbMinSize = None;
1116 self.oTestFsObj = oTestFsObj # type: testfileset.TestFsObj
1117
1118 def execute(self, oTstDrv, oGstCtrlSession, sMsgPrefix):
1119 """
1120 Execute the test step.
1121 """
1122 reporter.log2('tdStepStat: sPath=%s enmType=%s hrcExpected=%s fFound=%s fFollowLinks=%s'
1123 % (self.sPath, self.enmType, self.hrcExpected, self.fFound, self.fFollowLinks,));
1124
1125 # Don't execute non-file tests on older VBox version.
1126 if oTstDrv.fpApiVer >= 5.0 or self.enmType == vboxcon.FsObjType_File or not self.fFound:
1127 #
1128 # Call the API.
1129 #
1130 try:
1131 if oTstDrv.fpApiVer >= 5.0:
1132 oFsInfo = oGstCtrlSession.fsObjQueryInfo(self.sPath, self.fFollowLinks);
1133 else:
1134 oFsInfo = oGstCtrlSession.fileQueryInfo(self.sPath);
1135 except vbox.ComException as oXcpt:
1136 ## @todo: The error reporting in the API just plain sucks! Most of the errors are
1137 ## VBOX_E_IPRT_ERROR and there seems to be no way to distinguish between
1138 ## non-existing files/path and a lot of other errors. Fix API and test!
1139 if not self.fFound:
1140 return True;
1141 if vbox.ComError.equal(oXcpt, self.hrcExpected): # Is this an expected failure?
1142 return True;
1143 return reporter.errorXcpt('%s: Unexpected exception for exiting path "%s" (enmType=%s, hrcExpected=%s):'
1144 % (sMsgPrefix, self.sPath, self.enmType, self.hrcExpected,));
1145 except:
1146 return reporter.errorXcpt('%s: Unexpected exception in tdStepStat::execute (%s)'
1147 % (sMsgPrefix, self.sPath,));
1148 if oFsInfo is None:
1149 return reporter.error('%s: "%s" got None instead of IFsObjInfo instance!' % (sMsgPrefix, self.sPath,));
1150
1151 #
1152 # Check type expectations.
1153 #
1154 try:
1155 enmType = oFsInfo.type;
1156 except:
1157 return reporter.errorXcpt('%s: Unexpected exception in reading "IFsObjInfo::type"' % (sMsgPrefix,));
1158 if enmType != self.enmType:
1159 return reporter.error('%s: "%s" has type %s, expected %s'
1160 % (sMsgPrefix, self.sPath, enmType, self.enmType));
1161
1162 #
1163 # Check size expectations.
1164 # Note! This is unicode string here on windows, for some reason.
1165 # long long mapping perhaps?
1166 #
1167 try:
1168 cbObject = long(oFsInfo.objectSize);
1169 except:
1170 return reporter.errorXcpt('%s: Unexpected exception in reading "IFsObjInfo::objectSize"'
1171 % (sMsgPrefix,));
1172 if self.cbExactSize is not None \
1173 and cbObject != self.cbExactSize:
1174 return reporter.error('%s: "%s" has size %s bytes, expected %s bytes'
1175 % (sMsgPrefix, self.sPath, cbObject, self.cbExactSize));
1176 if self.cbMinSize is not None \
1177 and cbObject < self.cbMinSize:
1178 return reporter.error('%s: "%s" has size %s bytes, expected as least %s bytes'
1179 % (sMsgPrefix, self.sPath, cbObject, self.cbMinSize));
1180 return True;
1181
1182class tdStepStatDir(tdStepStat):
1183 """ Checks for an existing directory. """
1184 def __init__(self, sDirPath, oTestDir = None):
1185 tdStepStat.__init__(self, sPath = sDirPath, enmType = vboxcon.FsObjType_Directory, oTestFsObj = oTestDir);
1186
1187class tdStepStatDirEx(tdStepStatDir):
1188 """ Checks for an existing directory given a TestDir object. """
1189 def __init__(self, oTestDir): # type: (testfileset.TestDir)
1190 tdStepStatDir.__init__(self, oTestDir.sPath, oTestDir);
1191
1192class tdStepStatFile(tdStepStat):
1193 """ Checks for an existing file """
1194 def __init__(self, sFilePath = None, oTestFile = None):
1195 tdStepStat.__init__(self, sPath = sFilePath, enmType = vboxcon.FsObjType_File, oTestFsObj = oTestFile);
1196
1197class tdStepStatFileEx(tdStepStatFile):
1198 """ Checks for an existing file given a TestFile object. """
1199 def __init__(self, oTestFile): # type: (testfileset.TestFile)
1200 tdStepStatFile.__init__(self, oTestFile.sPath, oTestFile);
1201
1202class tdStepStatFileSize(tdStepStat):
1203 """ Checks for an existing file of a given expected size.. """
1204 def __init__(self, sFilePath, cbExactSize = 0):
1205 tdStepStat.__init__(self, sPath = sFilePath, enmType = vboxcon.FsObjType_File);
1206 self.cbExactSize = cbExactSize;
1207
1208class tdStepStatFileNotFound(tdStepStat):
1209 """ Checks for an existing directory. """
1210 def __init__(self, sPath):
1211 tdStepStat.__init__(self, sPath = sPath, fFound = False);
1212
1213class tdStepStatPathNotFound(tdStepStat):
1214 """ Checks for an existing directory. """
1215 def __init__(self, sPath):
1216 tdStepStat.__init__(self, sPath = sPath, fFound = False);
1217
1218
1219#
1220#
1221#
1222
1223class tdTestSessionFileRefs(tdTestGuestCtrlBase):
1224 """
1225 Tests session file (IGuestFile) reference counting.
1226 """
1227 def __init__(self, cRefs = 0):
1228 tdTestGuestCtrlBase.__init__(self);
1229 self.cRefs = cRefs;
1230
1231class tdTestSessionDirRefs(tdTestGuestCtrlBase):
1232 """
1233 Tests session directory (IGuestDirectory) reference counting.
1234 """
1235 def __init__(self, cRefs = 0):
1236 tdTestGuestCtrlBase.__init__(self);
1237 self.cRefs = cRefs;
1238
1239class tdTestSessionProcRefs(tdTestGuestCtrlBase):
1240 """
1241 Tests session process (IGuestProcess) reference counting.
1242 """
1243 def __init__(self, cRefs = 0):
1244 tdTestGuestCtrlBase.__init__(self);
1245 self.cRefs = cRefs;
1246
1247class tdTestUpdateAdditions(tdTestGuestCtrlBase):
1248 """
1249 Test updating the Guest Additions inside the guest.
1250 """
1251 def __init__(self, sSrc = "", asArgs = None, afFlags = None, oCreds = None):
1252 tdTestGuestCtrlBase.__init__(self, oCreds = oCreds);
1253 self.sSrc = sSrc;
1254 self.asArgs = asArgs;
1255 self.afFlags = afFlags;
1256
1257class tdTestResult(object):
1258 """
1259 Base class for test results.
1260 """
1261 def __init__(self, fRc = False):
1262 ## The overall test result.
1263 self.fRc = fRc;
1264
1265class tdTestResultFailure(tdTestResult):
1266 """
1267 Base class for test results.
1268 """
1269 def __init__(self):
1270 tdTestResult.__init__(self, fRc = False);
1271
1272class tdTestResultSuccess(tdTestResult):
1273 """
1274 Base class for test results.
1275 """
1276 def __init__(self):
1277 tdTestResult.__init__(self, fRc = True);
1278
1279class tdTestResultDirRead(tdTestResult):
1280 """
1281 Test result for reading guest directories.
1282 """
1283 def __init__(self, fRc = False, cFiles = 0, cDirs = 0, cOthers = None):
1284 tdTestResult.__init__(self, fRc = fRc);
1285 self.cFiles = cFiles;
1286 self.cDirs = cDirs;
1287 self.cOthers = cOthers;
1288
1289class tdTestResultExec(tdTestResult):
1290 """
1291 Holds a guest process execution test result,
1292 including the exit code, status + afFlags.
1293 """
1294 def __init__(self, fRc = False, uExitStatus = 500, iExitCode = 0, sBuf = None, cbBuf = 0, cbStdOut = None, cbStdErr = None):
1295 tdTestResult.__init__(self);
1296 ## The overall test result.
1297 self.fRc = fRc;
1298 ## Process exit stuff.
1299 self.uExitStatus = uExitStatus;
1300 self.iExitCode = iExitCode;
1301 ## Desired buffer length returned back from stdout/stderr.
1302 self.cbBuf = cbBuf;
1303 ## Desired buffer result from stdout/stderr. Use with caution!
1304 self.sBuf = sBuf;
1305 self.cbStdOut = cbStdOut;
1306 self.cbStdErr = cbStdErr;
1307
1308class tdTestResultFileStat(tdTestResult):
1309 """
1310 Test result for stat'ing guest files.
1311 """
1312 def __init__(self, fRc = False,
1313 cbSize = 0, eFileType = 0):
1314 tdTestResult.__init__(self, fRc = fRc);
1315 self.cbSize = cbSize;
1316 self.eFileType = eFileType;
1317 ## @todo Add more information.
1318
1319class tdTestResultFileReadWrite(tdTestResult):
1320 """
1321 Test result for reading + writing guest directories.
1322 """
1323 def __init__(self, fRc = False,
1324 cbProcessed = 0, offFile = 0, abBuf = None):
1325 tdTestResult.__init__(self, fRc = fRc);
1326 self.cbProcessed = cbProcessed;
1327 self.offFile = offFile;
1328 self.abBuf = abBuf;
1329
1330class tdTestResultSession(tdTestResult):
1331 """
1332 Test result for guest session counts.
1333 """
1334 def __init__(self, fRc = False, cNumSessions = 0):
1335 tdTestResult.__init__(self, fRc = fRc);
1336 self.cNumSessions = cNumSessions;
1337
1338class tdDebugSettings(object):
1339 """
1340 Contains local test debug settings.
1341 """
1342 def __init__(self, sImgPath = None):
1343 self.sImgPath = sImgPath;
1344 self.sVBoxServiceLogPath = '';
1345 self.fNoExit = False;
1346
1347class SubTstDrvAddGuestCtrl(base.SubTestDriverBase):
1348 """
1349 Sub-test driver for executing guest control (VBoxService, IGuest) tests.
1350 """
1351
1352 def __init__(self, oTstDrv):
1353 base.SubTestDriverBase.__init__(self, oTstDrv, 'add-guest-ctrl', 'Guest Control');
1354
1355 ## @todo base.TestBase.
1356 self.asTestsDef = [
1357 'debug',
1358 'session_basic', 'session_env', 'session_file_ref', 'session_dir_ref', 'session_proc_ref', 'session_reboot',
1359 'exec_basic', 'exec_timeout',
1360 'dir_create', 'dir_create_temp', 'dir_read',
1361 'file_open', 'file_remove', 'file_stat', 'file_read', 'file_write',
1362 'copy_to', 'copy_from',
1363 'update_additions'
1364 ];
1365 self.asTests = self.asTestsDef;
1366 self.fSkipKnownBugs = False;
1367 self.oTestFiles = None # type: vboxtestfileset.TestFileSet
1368 self.oDebug = tdDebugSettings();
1369
1370 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
1371 if asArgs[iArg] == '--add-guest-ctrl-tests':
1372 iArg += 1;
1373 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1374 if asArgs[iArg] == 'all': # Nice for debugging scripts.
1375 self.asTests = self.asTestsDef;
1376 else:
1377 self.asTests = asArgs[iArg].split(':');
1378 for s in self.asTests:
1379 if s not in self.asTestsDef:
1380 raise base.InvalidOption('The "--add-guest-ctrl-tests" value "%s" is not valid; valid values are: %s'
1381 % (s, ' '.join(self.asTestsDef)));
1382 return iNext;
1383 if asArgs[iArg] == '--add-guest-ctrl-skip-known-bugs':
1384 self.fSkipKnownBugs = True;
1385 return iArg + 1;
1386 if asArgs[iArg] == '--no-add-guest-ctrl-skip-known-bugs':
1387 self.fSkipKnownBugs = False;
1388 return iArg + 1;
1389 if asArgs[iArg] == '--add-guest-ctrl-debug-img':
1390 iArg += 1;
1391 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1392 self.oDebug.sImgPath = asArgs[iArg];
1393 return iNext;
1394 if asArgs[iArg] == '--add-guest-ctrl-debug-no-exit':
1395 self.oDebug.fNoExit = True;
1396 return iArg + 1;
1397 return iArg;
1398
1399 def showUsage(self):
1400 base.SubTestDriverBase.showUsage(self);
1401 reporter.log(' --add-guest-ctrl-tests <s1[:s2[:]]>');
1402 reporter.log(' Default: %s (all)' % (':'.join(self.asTestsDef)));
1403 reporter.log(' --add-guest-ctrl-skip-known-bugs');
1404 reporter.log(' Skips known bugs. Default: --no-add-guest-ctrl-skip-known-bugs');
1405 reporter.log('Debugging:');
1406 reporter.log(' --add-guest-ctrl-debug-img');
1407 reporter.log(' Sets VBoxService image to deploy for debugging');
1408 reporter.log(' --add-guest-ctrl-debug-no-exit');
1409 reporter.log(' Does not tear down and exit the test driver after running the tests');
1410 return True;
1411
1412 def testIt(self, oTestVm, oSession, oTxsSession):
1413 """
1414 Executes the test.
1415
1416 Returns fRc, oTxsSession. The latter may have changed.
1417 """
1418 reporter.log("Active tests: %s" % (self.asTests,));
1419
1420 # The tests. Must-succeed tests should be first.
1421 atTests = [
1422 ( True, self.prepareGuestForTesting, None, 'Preparations',),
1423 ( True, self.prepareGuestForDebugging, None, 'Manaul Debugging',),
1424 ( True, self.testGuestCtrlSession, 'session_basic', 'Session Basics',),
1425 ( True, self.testGuestCtrlExec, 'exec_basic', 'Execution',),
1426 ( False, self.testGuestCtrlExecTimeout, 'exec_timeout', 'Execution Timeouts',),
1427 ( False, self.testGuestCtrlSessionEnvironment, 'session_env', 'Session Environment',),
1428 ( False, self.testGuestCtrlSessionFileRefs, 'session_file_ref', 'Session File References',),
1429 #( False, self.testGuestCtrlSessionDirRefs, 'session_dir_ref', 'Session Directory References',),
1430 ( False, self.testGuestCtrlSessionProcRefs, 'session_proc_ref', 'Session Process References',),
1431 ( False, self.testGuestCtrlDirCreate, 'dir_create', 'Creating directories',),
1432 ( False, self.testGuestCtrlDirCreateTemp, 'dir_create_temp', 'Creating temporary directories',),
1433 ( False, self.testGuestCtrlDirRead, 'dir_read', 'Reading directories',),
1434 ( False, self.testGuestCtrlCopyTo, 'copy_to', 'Copy to guest',),
1435 ( False, self.testGuestCtrlCopyFrom, 'copy_from', 'Copy from guest',),
1436 ( False, self.testGuestCtrlFileStat, 'file_stat', 'Querying file information (stat)',),
1437 ( False, self.testGuestCtrlFileOpen, 'file_open', 'File open',),
1438 ( False, self.testGuestCtrlFileRead, 'file_read', 'File read',),
1439 ( False, self.testGuestCtrlFileWrite, 'file_write', 'File write',),
1440 ( False, self.testGuestCtrlFileRemove, 'file_remove', 'Removing files',), # Destroys prepped files.
1441 ( False, self.testGuestCtrlSessionReboot, 'session_reboot', 'Session w/ Guest Reboot',), # May zap /tmp.
1442 ( False, self.testGuestCtrlUpdateAdditions, 'update_additions', 'Updating Guest Additions',),
1443 ];
1444
1445 fRc = True;
1446 for fMustSucceed, fnHandler, sShortNm, sTestNm in atTests:
1447 reporter.testStart(sTestNm);
1448
1449 if sShortNm is None or sShortNm in self.asTests:
1450 # Returns (fRc, oTxsSession, oSession) - but only the first one is mandatory.
1451 aoResult = fnHandler(oSession, oTxsSession, oTestVm);
1452 if aoResult is None or isinstance(aoResult, bool):
1453 fRcTest = aoResult;
1454 else:
1455 fRcTest = aoResult[0];
1456 if len(aoResult) > 1:
1457 oTxsSession = aoResult[1];
1458 if len(aoResult) > 2:
1459 oSession = aoResult[2];
1460 assert len(aoResult) == 3;
1461 else:
1462 fRcTest = None;
1463
1464 if fRcTest is False and reporter.testErrorCount() == 0:
1465 fRcTest = reporter.error('Buggy test! Returned False w/o logging the error!');
1466 if reporter.testDone(fRcTest is None)[1] != 0:
1467 fRcTest = False;
1468 fRc = False;
1469
1470 # Stop execution if this is a must-succeed test and it failed.
1471 if fRcTest is False and fMustSucceed is True:
1472 reporter.log('Skipping any remaining tests since the previous one failed.');
1473 break;
1474
1475 return (fRc, oTxsSession);
1476
1477 #
1478 # Guest locations.
1479 #
1480
1481 @staticmethod
1482 def getGuestTempDir(oTestVm):
1483 """
1484 Helper for finding a temporary directory in the test VM.
1485
1486 Note! It may be necessary to create it!
1487 """
1488 if oTestVm.isWindows():
1489 return "C:\\Temp";
1490 if oTestVm.isOS2():
1491 return "C:\\Temp";
1492 return '/var/tmp';
1493
1494 @staticmethod
1495 def getGuestSystemDir(oTestVm):
1496 """
1497 Helper for finding a system directory in the test VM that we can play around with.
1498
1499 On Windows this is always the System32 directory, so this function can be used as
1500 basis for locating other files in or under that directory.
1501 """
1502 if oTestVm.isWindows():
1503 if oTestVm.sKind in ['WindowsNT4', 'WindowsNT3x',]:
1504 return 'C:\\Winnt\\System32';
1505 return 'C:\\Windows\\System32';
1506 if oTestVm.isOS2():
1507 return 'C:\\OS2\\DLL';
1508 return "/bin";
1509
1510 @staticmethod
1511 def getGuestSystemShell(oTestVm):
1512 """
1513 Helper for finding the default system shell in the test VM.
1514 """
1515 if oTestVm.isWindows():
1516 return SubTstDrvAddGuestCtrl.getGuestSystemDir(oTestVm) + '\\cmd.exe';
1517 if oTestVm.isOS2():
1518 return SubTstDrvAddGuestCtrl.getGuestSystemDir(oTestVm) + '\\..\\CMD.EXE';
1519 return "/bin/sh";
1520
1521 @staticmethod
1522 def getGuestSystemFileForReading(oTestVm):
1523 """
1524 Helper for finding a file in the test VM that we can read.
1525 """
1526 if oTestVm.isWindows():
1527 return SubTstDrvAddGuestCtrl.getGuestSystemDir(oTestVm) + '\\ntdll.dll';
1528 if oTestVm.isOS2():
1529 return SubTstDrvAddGuestCtrl.getGuestSystemDir(oTestVm) + '\\DOSCALL1.DLL';
1530 return "/bin/sh";
1531
1532 def prepareGuestForDebugging(self, oSession, oTxsSession, oTestVm): # pylint: disable=unused-argument
1533 """
1534 Prepares a guest for (manual) debugging.
1535
1536 This involves copying over and invoking a the locally built VBoxService binary.
1537 """
1538
1539 if self.oDebug.sImgPath is None: # If no debugging enabled, bail out.
1540 return True
1541
1542 reporter.log('Preparing for debugging ...');
1543
1544 try:
1545
1546 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1547
1548 if oTestVm.isLinux():
1549 reporter.log('Uploading %s ...' % self.oDebug.sImgPath);
1550 sFileVBoxServiceHst = self.oDebug.sImgPath;
1551 sFileVBoxServiceGst = "/tmp/VBoxService-txs";
1552 oTxsSession.syncUploadFile(sFileVBoxServiceHst, sFileVBoxServiceGst);
1553 oTxsSession.syncChMod(sFileVBoxServiceGst, 0o755);
1554 reporter.log('Executing VBoxService (in background)...');
1555 oTxsSession.syncExec(sFileVBoxServiceGst, (sFileVBoxServiceGst, "-vvvv", "--only-control", \
1556 "--logfile", "/tmp/VBoxService-txs.log") );
1557 elif oTestVm.isWindows():
1558 reporter.log('Uploading %s ...' % self.oDebug.sImgPath);
1559 sFileVBoxServiceHst = self.oDebug.sImgPath;
1560 sFileVBoxServiceGst = os.path.join(SubTstDrvAddGuestCtrl.getGuestSystemDir(oTestVm), 'VBoxService.exe');
1561 oTxsSession.syncUploadFile(sFileVBoxServiceHst, sFileVBoxServiceGst);
1562 sPathSC = os.path.join(SubTstDrvAddGuestCtrl.getGuestSystemDir(oTestVm), 'sc.exe');
1563 oTxsSession.syncExec(sPathSC, (sPathSC, "stop", "VBoxService") );
1564 time.sleep(5);
1565 oTxsSession.syncExec(sPathSC, (sPathSC, "start", "VBoxService") );
1566
1567 else: ## @todo Implement others.
1568 reporter.log('Debugging not available on this guest OS yet, skipping ...');
1569
1570 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1571
1572 except:
1573 return reporter.errorXcpt('Unable to prepare for debugging');
1574
1575 return True;
1576
1577 #
1578 # VBoxService handling.
1579 #
1580 def vboxServiceControl(self, oTxsSession, oTestVm, fStart):
1581 """
1582 Controls VBoxService on the guest by starting or stopping the service.
1583 Returns success indicator.
1584 """
1585
1586 fRc = True;
1587
1588 if oTestVm.isWindows():
1589 sPathSC = os.path.join(self.getGuestSystemDir(oTestVm), 'sc.exe');
1590 if fStart is True:
1591 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Starting VBoxService with verbose logging', 30 * 1000, \
1592 sPathSC, (sPathSC, 'start', 'VBoxService'));
1593 else:
1594 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Stopping VBoxService', 30 * 1000, \
1595 sPathSC, (sPathSC, 'stop', 'VBoxService'));
1596 else:
1597 reporter.log('Controlling VBoxService not supported for this guest yet');
1598
1599 return fRc;
1600
1601 def waitForGuestFacility(self, oSession, eFacilityType, sDesc,
1602 eFacilityStatus, cMsTimeout = 30 * 1000):
1603 """
1604 Waits for a guest facility to enter a certain status.
1605 By default the "Active" status is being used.
1606 """
1607
1608 reporter.log('Waiting for Guest Additions facility "%s" to change to status %s (%dms timeout)...'
1609 % (sDesc, str(eFacilityStatus), cMsTimeout));
1610
1611 fRc = False;
1612
1613 eStatusOld = vboxcon.AdditionsFacilityStatus_Unknown;
1614 tsStart = base.timestampMilli();
1615 while base.timestampMilli() - tsStart < cMsTimeout:
1616 try:
1617 eStatus, _ = oSession.o.console.guest.getFacilityStatus(eFacilityType);
1618 except:
1619 reporter.errorXcpt('Getting facility status failed');
1620 break;
1621 if eStatus != eStatusOld:
1622 reporter.log('Status is now %s' % (str(eStatus)));
1623 eStatusOld = eStatus;
1624 if eStatus == eFacilityStatus:
1625 fRc = True;
1626 break;
1627 self.oTstDrv.sleep(5); # Do some busy waiting.
1628
1629 if not fRc:
1630 reporter.testFailure('Waiting for Guest Additions facility "%s" timed out' % (sDesc));
1631 else:
1632 reporter.testFailure('Guest Additions facility "%s" reached requested status %s after %dms'
1633 % (sDesc, str(eFacilityStatus), base.timestampMilli() - tsStart));
1634
1635 return fRc;
1636
1637 #
1638 # Guest test files.
1639 #
1640
1641 def prepareGuestForTesting(self, oSession, oTxsSession, oTestVm):
1642 """
1643 Prepares the VM for testing, uploading a bunch of files and stuff via TXS.
1644 Returns success indicator.
1645 """
1646 _ = oSession;
1647
1648 #
1649 # Wait for VBoxService to come up.
1650 #
1651 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1652 vboxcon.AdditionsFacilityStatus_Active);
1653 if not fRc:
1654 return (False, oTxsSession);
1655
1656 #
1657 # Make sure the temporary directory exists.
1658 #
1659 for sDir in [self.getGuestTempDir(oTestVm), ]:
1660 if oTxsSession.syncMkDirPath(sDir, 0o777) is not True:
1661 return reporter.error('Failed to create directory "%s"!' % (sDir,));
1662
1663 #
1664 # Enable VBoxService verbose logging.
1665 #
1666 self.oDebug.sVBoxServiceLogPath = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), "VBoxService");
1667 if oTxsSession.syncMkDirPath(self.oDebug.sVBoxServiceLogPath, 0o777) is not True:
1668 return reporter.error('Failed to create directory "%s"!' % (self.oDebug.sVBoxServiceLogPath,));
1669 sPathLogFile = oTestVm.pathJoin(self.oDebug.sVBoxServiceLogPath, 'VBoxService.log');
1670
1671 reporter.log('VBoxService logs will be stored in "%s"' % (self.oDebug.sVBoxServiceLogPath,));
1672
1673 if oTestVm.isWindows():
1674 sPathRegExe = oTestVm.pathJoin(self.getGuestSystemDir(oTestVm), 'reg.exe');
1675 sPathVBoxServiceExe = oTestVm.pathJoin(self.getGuestSystemDir(oTestVm), 'VBoxService.exe');
1676 sImagePath = '%s -vvvv --logfile %s' % (sPathVBoxServiceExe, sPathLogFile);
1677 self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging (via registry)', 30 * 1000,
1678 sPathRegExe,
1679 (sPathRegExe, 'add',
1680 '"HKLM\\SYSTEM\\CurrentControlSet\\Services\\VBoxService"',
1681 '/v', 'ImagePath', '/t', 'REG_SZ', '/d', sImagePath, '/f'));
1682
1683 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1684 time.sleep(5);
1685 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1686
1687 else:
1688 reporter.log('Verbose logging for VBoxService not supported for this guest yet');
1689
1690 #
1691 # Generate and upload some random files and dirs to the guest.
1692 # Note! Make sure we don't run into too-long-path issues when using
1693 # the test files on the host if.
1694 #
1695 cchGst = len(self.getGuestTempDir(oTestVm)) + 1 + len('addgst-1') + 1;
1696 cchHst = len(self.oTstDrv.sScratchPath) + 1 + len('copyto/addgst-1') + 1;
1697 cchMaxPath = 230;
1698 if cchHst > cchGst:
1699 cchMaxPath -= cchHst - cchGst;
1700 reporter.log('cchMaxPath=%s (cchHst=%s, cchGst=%s)' % (cchMaxPath, cchHst, cchGst,));
1701 asCompatibleWith = None;
1702 if oTestVm.isWindows():
1703 asCompatibleWith = [ 'win' ];
1704 self.oTestFiles = vboxtestfileset.TestFileSet(oTestVm,
1705 self.getGuestTempDir(oTestVm), 'addgst-1',
1706 cchMaxPath = cchMaxPath, asCompatibleWith = asCompatibleWith);
1707 return self.oTestFiles.upload(oTxsSession, self.oTstDrv);
1708
1709
1710 #
1711 # gctrlXxxx stuff.
1712 #
1713
1714 def gctrlCopyFileFrom(self, oGuestSession, oTest, fExpected):
1715 """
1716 Helper function to copy a single file from the guest to the host.
1717 """
1718 #
1719 # Do the copying.
1720 #
1721 reporter.log2('Copying guest file "%s" to host "%s"' % (oTest.sSrc, oTest.sDst));
1722 try:
1723 if self.oTstDrv.fpApiVer >= 5.0:
1724 oCurProgress = oGuestSession.fileCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1725 else:
1726 oCurProgress = oGuestSession.copyFrom(oTest.sSrc, oTest.sDst, oTest.afFlags);
1727 except:
1728 reporter.maybeErrXcpt(fExpected, 'Copy from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1729 return False;
1730 if oCurProgress is None:
1731 return reporter.error('No progress object returned');
1732 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlFileCopyFrom");
1733 oProgress.wait();
1734 if not oProgress.isSuccess():
1735 oProgress.logResult(fIgnoreErrors = not fExpected);
1736 return False;
1737
1738 #
1739 # Check the result if we can.
1740 #
1741 if oTest.oSrc:
1742 assert isinstance(oTest.oSrc, testfileset.TestFile);
1743 sDst = oTest.sDst;
1744 if os.path.isdir(sDst):
1745 sDst = os.path.join(sDst, oTest.oSrc.sName);
1746 try:
1747 oFile = open(sDst, 'rb');
1748 except:
1749 return reporter.errorXcpt('open(%s) failed during verfication' % (sDst,));
1750 fEqual = oTest.oSrc.equalFile(oFile);
1751 oFile.close();
1752 if not fEqual:
1753 return reporter.error('Content differs for "%s"' % (sDst,));
1754
1755 return True;
1756
1757 def __compareTestDir(self, oDir, sHostPath): # type: (testfileset.TestDir, str) -> bool
1758 """
1759 Recursively compare the content of oDir and sHostPath.
1760
1761 Returns True on success, False + error logging on failure.
1762
1763 Note! This ASSUMES that nothing else was copied to sHostPath!
1764 """
1765 #
1766 # First check out all the entries and files in the directory.
1767 #
1768 dLeftUpper = dict(oDir.dChildrenUpper);
1769 try:
1770 asEntries = os.listdir(sHostPath);
1771 except:
1772 return reporter.errorXcpt('os.listdir(%s) failed' % (sHostPath,));
1773
1774 fRc = True;
1775 for sEntry in asEntries:
1776 sEntryUpper = sEntry.upper();
1777 if sEntryUpper not in dLeftUpper:
1778 fRc = reporter.error('Unexpected entry "%s" in "%s"' % (sEntry, sHostPath,));
1779 else:
1780 oFsObj = dLeftUpper[sEntryUpper];
1781 del dLeftUpper[sEntryUpper];
1782
1783 if isinstance(oFsObj, testfileset.TestFile):
1784 sFilePath = os.path.join(sHostPath, oFsObj.sName);
1785 try:
1786 oFile = open(sFilePath, 'rb');
1787 except:
1788 fRc = reporter.errorXcpt('open(%s) failed during verfication' % (sFilePath,));
1789 else:
1790 fEqual = oFsObj.equalFile(oFile);
1791 oFile.close();
1792 if not fEqual:
1793 fRc = reporter.error('Content differs for "%s"' % (sFilePath,));
1794
1795 # List missing entries:
1796 for sKey in dLeftUpper:
1797 oEntry = dLeftUpper[sKey];
1798 fRc = reporter.error('%s: Missing %s "%s" (src path: %s)'
1799 % (sHostPath, oEntry.sName,
1800 'file' if isinstance(oEntry, testfileset.TestFile) else 'directory', oEntry.sPath));
1801
1802 #
1803 # Recurse into subdirectories.
1804 #
1805 for oFsObj in oDir.aoChildren:
1806 if isinstance(oFsObj, testfileset.TestDir):
1807 fRc = self.__compareTestDir(oFsObj, os.path.join(sHostPath, oFsObj.sName)) and fRc;
1808 return fRc;
1809
1810 def gctrlCopyDirFrom(self, oGuestSession, oTest, fExpected):
1811 """
1812 Helper function to copy a directory from the guest to the host.
1813 """
1814 #
1815 # Do the copying.
1816 #
1817 reporter.log2('Copying guest dir "%s" to host "%s"' % (oTest.sSrc, oTest.sDst));
1818 try:
1819 oCurProgress = oGuestSession.directoryCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1820 except:
1821 reporter.maybeErrXcpt(fExpected, 'Copy dir from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1822 return False;
1823 if oCurProgress is None:
1824 return reporter.error('No progress object returned');
1825
1826 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlDirCopyFrom");
1827 oProgress.wait();
1828 if not oProgress.isSuccess():
1829 oProgress.logResult(fIgnoreErrors = not fExpected);
1830 return False;
1831
1832 #
1833 # Check the result if we can.
1834 #
1835 if oTest.oSrc:
1836 assert isinstance(oTest.oSrc, testfileset.TestDir);
1837 sDst = oTest.sDst;
1838 if oTest.fIntoDst:
1839 return self.__compareTestDir(oTest.oSrc, os.path.join(sDst, oTest.oSrc.sName));
1840 oDummy = testfileset.TestDir(None, 'dummy');
1841 oDummy.aoChildren = [oTest.oSrc,]
1842 oDummy.dChildrenUpper = { oTest.oSrc.sName.upper(): oTest.oSrc, };
1843 return self.__compareTestDir(oDummy, sDst);
1844 return True;
1845
1846 def gctrlCopyFileTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1847 """
1848 Helper function to copy a single file from the host to the guest.
1849 """
1850 reporter.log2('Copying host file "%s" to guest "%s" (flags %s)' % (sSrc, sDst, afFlags));
1851 try:
1852 if self.oTstDrv.fpApiVer >= 5.0:
1853 oCurProgress = oGuestSession.fileCopyToGuest(sSrc, sDst, afFlags);
1854 else:
1855 oCurProgress = oGuestSession.copyTo(sSrc, sDst, afFlags);
1856 except:
1857 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
1858 return False;
1859
1860 if oCurProgress is None:
1861 return reporter.error('No progress object returned');
1862 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
1863
1864 try:
1865 oProgress.wait();
1866 if not oProgress.isSuccess():
1867 oProgress.logResult(fIgnoreErrors = not fIsError);
1868 return False;
1869 except:
1870 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
1871 return False;
1872 return True;
1873
1874 def gctrlCopyDirTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1875 """
1876 Helper function to copy a directory tree from the host to the guest.
1877 """
1878 reporter.log2('Copying host directory "%s" to guest "%s" (flags %s)' % (sSrc, sDst, afFlags));
1879 try:
1880 oCurProgress = oGuestSession.directoryCopyToGuest(sSrc, sDst, afFlags);
1881 except:
1882 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
1883 return False;
1884
1885 if oCurProgress is None:
1886 return reporter.error('No progress object returned');
1887 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
1888
1889 try:
1890 oProgress.wait();
1891 if not oProgress.isSuccess():
1892 oProgress.logResult(fIgnoreErrors = not fIsError);
1893 return False;
1894 except:
1895 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
1896 return False;
1897 return True;
1898
1899 def gctrlCreateDir(self, oTest, oRes, oGuestSession):
1900 """
1901 Helper function to create a guest directory specified in the current test.
1902 """
1903 reporter.log2('Creating directory "%s"' % (oTest.sDirectory,));
1904 try:
1905 oGuestSession.directoryCreate(oTest.sDirectory, oTest.fMode, oTest.afFlags);
1906 except:
1907 reporter.maybeErrXcpt(oRes.fRc, 'Failed to create "%s" fMode=%o afFlags=%s'
1908 % (oTest.sDirectory, oTest.fMode, oTest.afFlags,));
1909 return not oRes.fRc;
1910 if oRes.fRc is not True:
1911 return reporter.error('Did not expect to create directory "%s"!' % (oTest.sDirectory,));
1912
1913 # Check if the directory now exists.
1914 try:
1915 if self.oTstDrv.fpApiVer >= 5.0:
1916 fDirExists = oGuestSession.directoryExists(oTest.sDirectory, False);
1917 else:
1918 fDirExists = oGuestSession.directoryExists(oTest.sDirectory);
1919 except:
1920 return reporter.errorXcpt('directoryExists failed on "%s"!' % (oTest.sDirectory,));
1921 if not fDirExists:
1922 return reporter.errorXcpt('directoryExists returned False on "%s" after directoryCreate succeeded!'
1923 % (oTest.sDirectory,));
1924 return True;
1925
1926 def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, sSubDir = None):
1927 """
1928 Helper function to recursively read a guest directory tree specified in the current test.
1929 """
1930 sDir = oTest.sDirectory;
1931 sFilter = oTest.sFilter;
1932 afFlags = oTest.afFlags;
1933 oTestVm = oTest.oCreds.oTestVm;
1934 sCurDir = oTestVm.pathJoin(sDir, sSubDir) if sSubDir else sDir;
1935
1936 fRc = True; # Be optimistic.
1937 cDirs = 0; # Number of directories read.
1938 cFiles = 0; # Number of files read.
1939 cOthers = 0; # Other files.
1940
1941 # Open the directory:
1942 reporter.log2('Directory="%s", filter="%s", afFlags="%s"' % (sCurDir, sFilter, afFlags));
1943 try:
1944 oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
1945 except:
1946 reporter.maybeErrXcpt(fIsError, 'sCurDir=%s sFilter=%s afFlags=%s' % (sCurDir, sFilter, afFlags,))
1947 return (False, 0, 0, 0);
1948
1949 # Read the directory.
1950 while fRc is True:
1951 try:
1952 oFsObjInfo = oCurDir.read();
1953 except Exception as oXcpt:
1954 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
1955 if self.oTstDrv.fpApiVer > 5.2:
1956 reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
1957 else:
1958 # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
1959 reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
1960 fRc = False;
1961 else:
1962 reporter.log2('\tNo more directory entries for "%s"' % (sCurDir,));
1963 break;
1964
1965 try:
1966 sName = oFsObjInfo.name;
1967 eType = oFsObjInfo.type;
1968 except:
1969 fRc = reporter.errorXcpt();
1970 break;
1971
1972 if sName in ('.', '..', ):
1973 if eType != vboxcon.FsObjType_Directory:
1974 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
1975 % (sName, eType, vboxcon.FsObjType_Directory));
1976 elif eType == vboxcon.FsObjType_Directory:
1977 reporter.log2(' Directory "%s"' % oFsObjInfo.name);
1978 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
1979 oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
1980 fRc = aSubResult[0];
1981 cDirs += aSubResult[1] + 1;
1982 cFiles += aSubResult[2];
1983 cOthers += aSubResult[3];
1984 elif eType is vboxcon.FsObjType_File:
1985 reporter.log2(' File "%s"' % oFsObjInfo.name);
1986 cFiles += 1;
1987 elif eType is vboxcon.FsObjType_Symlink:
1988 reporter.log2(' Symlink "%s" -- not tested yet' % oFsObjInfo.name);
1989 cOthers += 1;
1990 elif oTestVm.isWindows() \
1991 or oTestVm.isOS2() \
1992 or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
1993 vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
1994 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
1995 (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
1996 else:
1997 cOthers += 1;
1998
1999 # Close the directory
2000 try:
2001 oCurDir.close();
2002 except:
2003 fRc = reporter.errorXcpt('sCurDir=%s' % (sCurDir));
2004
2005 return (fRc, cDirs, cFiles, cOthers);
2006
2007 def gctrlReadDirTree2(self, oGuestSession, oDir): # type: (testfileset.TestDir) -> bool
2008 """
2009 Helper function to recursively read a guest directory tree specified in the current test.
2010 """
2011
2012 #
2013 # Process the directory.
2014 #
2015
2016 # Open the directory:
2017 try:
2018 oCurDir = oGuestSession.directoryOpen(oDir.sPath, '', None);
2019 except:
2020 return reporter.errorXcpt('sPath=%s' % (oDir.sPath,));
2021
2022 # Read the directory.
2023 dLeftUpper = dict(oDir.dChildrenUpper);
2024 cDot = 0;
2025 cDotDot = 0;
2026 fRc = True;
2027 while True:
2028 try:
2029 oFsObjInfo = oCurDir.read();
2030 except Exception as oXcpt:
2031 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2032 fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath,));
2033 break;
2034
2035 try:
2036 sName = oFsObjInfo.name;
2037 eType = oFsObjInfo.type;
2038 cbFile = oFsObjInfo.objectSize;
2039 ## @todo check further attributes.
2040 except:
2041 fRc = reporter.errorXcpt();
2042 break;
2043
2044 # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
2045 if sName in ('.', '..', ):
2046 if eType != vboxcon.FsObjType_Directory:
2047 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2048 % (sName, eType, vboxcon.FsObjType_Directory));
2049 if sName == '.': cDot += 1;
2050 else: cDotDot += 1;
2051 else:
2052 # Find the child and remove it from the dictionary.
2053 sNameUpper = sName.upper();
2054 oFsObj = dLeftUpper.get(sNameUpper);
2055 if oFsObj is None:
2056 fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
2057 % (sName, oDir.sPath, eType, cbFile,));
2058 else:
2059 del dLeftUpper[sNameUpper];
2060
2061 # Check type
2062 if isinstance(oFsObj, testfileset.TestDir):
2063 if eType != vboxcon.FsObjType_Directory:
2064 fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
2065 % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
2066 elif isinstance(oFsObj, testfileset.TestFile):
2067 if eType != vboxcon.FsObjType_File:
2068 fRc = reporter.error('%s: expected file (%d), got eType=%d!'
2069 % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
2070 else:
2071 fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
2072
2073 # Check the name.
2074 if oFsObj.sName != sName:
2075 fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % (oFsObj.sPath, oFsObj.sName, sName,));
2076
2077 # Check the size if a file.
2078 if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
2079 fRc = reporter.error('%s: expected size %s, got %s instead!' % (oFsObj.sPath, oFsObj.cbContent, cbFile,));
2080
2081 ## @todo check timestamps and attributes.
2082
2083 # Close the directory
2084 try:
2085 oCurDir.close();
2086 except:
2087 fRc = reporter.errorXcpt('oDir.sPath=%s' % (oDir.sPath,));
2088
2089 # Any files left over?
2090 for sKey in dLeftUpper:
2091 oFsObj = dLeftUpper[sKey];
2092 fRc = reporter.error('%s: Was not returned! (%s)' % (oFsObj.sPath, type(oFsObj),));
2093
2094 # Check the dot and dot-dot counts.
2095 if cDot != 1:
2096 fRc = reporter.error('%s: Found %s "." entries, expected exactly 1!' % (oDir.sPath, cDot,));
2097 if cDotDot != 1:
2098 fRc = reporter.error('%s: Found %s ".." entries, expected exactly 1!' % (oDir.sPath, cDotDot,));
2099
2100 #
2101 # Recurse into subdirectories using info from oDir.
2102 #
2103 for oFsObj in oDir.aoChildren:
2104 if isinstance(oFsObj, testfileset.TestDir):
2105 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj) and fRc;
2106
2107 return fRc;
2108
2109 def gctrlExecDoTest(self, i, oTest, oRes, oGuestSession):
2110 """
2111 Wrapper function around gctrlExecute to provide more sanity checking
2112 when needed in actual execution tests.
2113 """
2114 reporter.log('Testing #%d, cmd="%s" ...' % (i, oTest.sCmd));
2115 fRcExec = self.gctrlExecute(oTest, oGuestSession, oRes.fRc);
2116 if fRcExec == oRes.fRc:
2117 fRc = True;
2118 if fRcExec is True:
2119 # Compare exit status / code on successful process execution.
2120 if oTest.uExitStatus != oRes.uExitStatus \
2121 or oTest.iExitCode != oRes.iExitCode:
2122 fRc = reporter.error('Test #%d (%s) failed: Got exit status + code %d,%d, expected %d,%d'
2123 % (i, oTest.asArgs, oTest.uExitStatus, oTest.iExitCode,
2124 oRes.uExitStatus, oRes.iExitCode));
2125
2126 # Compare test / result buffers on successful process execution.
2127 if oTest.sBuf is not None and oRes.sBuf is not None:
2128 if not utils.areBytesEqual(oTest.sBuf, oRes.sBuf):
2129 fRc = reporter.error('Test #%d (%s) failed: Got buffer\n%s (%d bytes), expected\n%s (%d bytes)'
2130 % (i, oTest.asArgs,
2131 map(hex, map(ord, oTest.sBuf)), len(oTest.sBuf),
2132 map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf)));
2133 reporter.log2('Test #%d passed: Buffers match (%d bytes)' % (i, len(oRes.sBuf)));
2134 elif oRes.sBuf and not oTest.sBuf:
2135 fRc = reporter.error('Test #%d (%s) failed: Got no buffer data, expected\n%s (%dbytes)' %
2136 (i, oTest.asArgs, map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf),));
2137
2138 if oRes.cbStdOut is not None and oRes.cbStdOut != oTest.cbStdOut:
2139 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stdout data, expected %d'
2140 % (i, oTest.asArgs, oTest.cbStdOut, oRes.cbStdOut));
2141 if oRes.cbStdErr is not None and oRes.cbStdErr != oTest.cbStdErr:
2142 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stderr data, expected %d'
2143 % (i, oTest.asArgs, oTest.cbStdErr, oRes.cbStdErr));
2144 else:
2145 fRc = reporter.error('Test #%d (%s) failed: Got %s, expected %s' % (i, oTest.asArgs, fRcExec, oRes.fRc));
2146 return fRc;
2147
2148 def gctrlExecute(self, oTest, oGuestSession, fIsError):
2149 """
2150 Helper function to execute a program on a guest, specified in the current test.
2151
2152 Note! This weirdo returns results (process exitcode and status) in oTest.
2153 """
2154 fRc = True; # Be optimistic.
2155
2156 # Reset the weird result stuff:
2157 oTest.cbStdOut = 0;
2158 oTest.cbStdErr = 0;
2159 oTest.sBuf = '';
2160 oTest.uExitStatus = 0;
2161 oTest.iExitCode = 0;
2162
2163 ## @todo Compare execution timeouts!
2164 #tsStart = base.timestampMilli();
2165
2166 try:
2167 reporter.log2('Using session user=%s, sDomain=%s, name=%s, timeout=%d'
2168 % (oGuestSession.user, oGuestSession.domain, oGuestSession.name, oGuestSession.timeout,));
2169 except:
2170 return reporter.errorXcpt();
2171
2172 #
2173 # Start the process:
2174 #
2175 reporter.log2('Executing sCmd=%s, afFlags=%s, timeoutMS=%d, asArgs=%s, asEnv=%s'
2176 % (oTest.sCmd, oTest.afFlags, oTest.timeoutMS, oTest.asArgs, oTest.aEnv,));
2177 try:
2178 oProcess = oGuestSession.processCreate(oTest.sCmd,
2179 oTest.asArgs if self.oTstDrv.fpApiVer >= 5.0 else oTest.asArgs[1:],
2180 oTest.aEnv, oTest.afFlags, oTest.timeoutMS);
2181 except:
2182 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (oTest.asArgs,));
2183 return False;
2184 if oProcess is None:
2185 return reporter.error('oProcess is None! (%s)' % (oTest.asArgs,));
2186
2187 #time.sleep(5); # try this if you want to see races here.
2188
2189 # Wait for the process to start properly:
2190 reporter.log2('Process start requested, waiting for start (%dms) ...' % (oTest.timeoutMS,));
2191 iPid = -1;
2192 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Start, ];
2193 try:
2194 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2195 except:
2196 reporter.maybeErrXcpt(fIsError, 'waitforArray failed for asArgs=%s' % (oTest.asArgs,));
2197 fRc = False;
2198 else:
2199 try:
2200 eStatus = oProcess.status;
2201 iPid = oProcess.PID;
2202 except:
2203 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2204 else:
2205 reporter.log2('Wait result returned: %d, current process status is: %d' % (eWaitResult, eStatus,));
2206
2207 #
2208 # Wait for the process to run to completion if necessary.
2209 #
2210 # Note! The above eWaitResult return value can be ignored as it will
2211 # (mostly) reflect the process status anyway.
2212 #
2213 if eStatus == vboxcon.ProcessStatus_Started:
2214
2215 # What to wait for:
2216 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, ];
2217 if vboxcon.ProcessCreateFlag_WaitForStdOut in oTest.afFlags:
2218 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdOut);
2219 if vboxcon.ProcessCreateFlag_WaitForStdErr in oTest.afFlags:
2220 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdErr);
2221 ## @todo Add vboxcon.ProcessWaitForFlag_StdIn.
2222
2223 reporter.log2('Process (PID %d) started, waiting for termination (%dms), aeWaitFor=%s ...'
2224 % (iPid, oTest.timeoutMS, aeWaitFor));
2225 acbFdOut = [0,0,0];
2226 while True:
2227 try:
2228 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2229 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2230 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2231 try: oProcess.close();
2232 except: pass;
2233 break;
2234 except:
2235 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2236 break;
2237 #reporter.log2('Wait returned: %d' % (eWaitResult,));
2238
2239 # Process output:
2240 for eFdResult, iFd, sFdNm in [ (vboxcon.ProcessWaitResult_StdOut, 1, 'stdout'),
2241 (vboxcon.ProcessWaitResult_StdErr, 2, 'stderr'), ]:
2242 if eWaitResult in (eFdResult, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2243 try:
2244 abBuf = oProcess.read(iFd, 64 * 1024, oTest.timeoutMS);
2245 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2246 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2247 try: oProcess.close();
2248 except: pass;
2249 except:
2250 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (oTest.asArgs,));
2251 else:
2252 if abBuf:
2253 reporter.log2('Process (PID %d) got %d bytes of %s data' % (iPid, len(abBuf), sFdNm,));
2254 for sLine in abBuf.splitlines():
2255 reporter.log('%s: %s' % (sFdNm, sLine));
2256 acbFdOut[iFd] += len(abBuf);
2257 oTest.sBuf = abBuf; ## @todo Figure out how to uniform + append!
2258
2259 ## Process input (todo):
2260 #if eWaitResult in (vboxcon.ProcessWaitResult_StdIn, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2261 # reporter.log2('Process (PID %d) needs stdin data' % (iPid,));
2262
2263 # Termination or error?
2264 if eWaitResult in (vboxcon.ProcessWaitResult_Terminate,
2265 vboxcon.ProcessWaitResult_Error,
2266 vboxcon.ProcessWaitResult_Timeout,):
2267 try: eStatus = oProcess.status;
2268 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2269 reporter.log2('Process (PID %d) reported terminate/error/timeout: %d, status: %d'
2270 % (iPid, eWaitResult, eStatus,));
2271 break;
2272
2273 # End of the wait loop.
2274 _, oTest.cbStdOut, oTest.cbStdErr = acbFdOut;
2275
2276 try: eStatus = oProcess.status;
2277 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2278 reporter.log2('Final process status (PID %d) is: %d' % (iPid, eStatus));
2279 reporter.log2('Process (PID %d) %d stdout, %d stderr' % (iPid, oTest.cbStdOut, oTest.cbStdErr));
2280
2281 #
2282 # Get the final status and exit code of the process.
2283 #
2284 try:
2285 oTest.uExitStatus = oProcess.status;
2286 oTest.iExitCode = oProcess.exitCode;
2287 except:
2288 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2289 reporter.log2('Process (PID %d) has exit code: %d; status: %d ' % (iPid, oTest.iExitCode, oTest.uExitStatus));
2290 return fRc;
2291
2292 def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2293 """
2294 Tests the guest session environment changes.
2295 """
2296 aoTests = [
2297 # Check basic operations.
2298 tdTestSessionEx([ # Initial environment is empty.
2299 tdStepSessionCheckEnv(),
2300 # Check clearing empty env.
2301 tdStepSessionClearEnv(),
2302 tdStepSessionCheckEnv(),
2303 # Check set.
2304 tdStepSessionSetEnv('FOO', 'BAR'),
2305 tdStepSessionCheckEnv(['FOO=BAR',]),
2306 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2307 tdStepSessionClearEnv(),
2308 tdStepSessionCheckEnv(),
2309 # Check unset.
2310 tdStepSessionUnsetEnv('BAR'),
2311 tdStepSessionCheckEnv(['BAR']),
2312 tdStepSessionClearEnv(),
2313 tdStepSessionCheckEnv(),
2314 # Set + unset.
2315 tdStepSessionSetEnv('FOO', 'BAR'),
2316 tdStepSessionCheckEnv(['FOO=BAR',]),
2317 tdStepSessionUnsetEnv('FOO'),
2318 tdStepSessionCheckEnv(['FOO']),
2319 # Bulk environment changes (via attrib) (shall replace existing 'FOO').
2320 tdStepSessionBulkEnv( ['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2321 tdStepSessionCheckEnv(['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2322 ]),
2323 tdTestSessionEx([ # Check that setting the same value several times works.
2324 tdStepSessionSetEnv('FOO','BAR'),
2325 tdStepSessionCheckEnv([ 'FOO=BAR',]),
2326 tdStepSessionSetEnv('FOO','BAR2'),
2327 tdStepSessionCheckEnv([ 'FOO=BAR2',]),
2328 tdStepSessionSetEnv('FOO','BAR3'),
2329 tdStepSessionCheckEnv([ 'FOO=BAR3',]),
2330 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2331 # Add a little unsetting to the mix.
2332 tdStepSessionSetEnv('BAR', 'BEAR'),
2333 tdStepSessionCheckEnv([ 'FOO=BAR3', 'BAR=BEAR',]),
2334 tdStepSessionUnsetEnv('FOO'),
2335 tdStepSessionCheckEnv([ 'FOO', 'BAR=BEAR',]),
2336 tdStepSessionSetEnv('FOO','BAR4'),
2337 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR',]),
2338 # The environment is case sensitive.
2339 tdStepSessionSetEnv('foo','BAR5'),
2340 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo=BAR5']),
2341 tdStepSessionUnsetEnv('foo'),
2342 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo']),
2343 ]),
2344 tdTestSessionEx([ # Bulk settings merges stuff, last entry standing.
2345 tdStepSessionBulkEnv(['FOO=bar', 'foo=bar', 'FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2346 tdStepSessionCheckEnv(['FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2347 tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2348 tdStepSessionBulkEnv(['2=1+1', 'FOO=doofus2', ]),
2349 tdStepSessionCheckEnv(['2=1+1', 'FOO=doofus2' ]),
2350 ]),
2351 # Invalid variable names.
2352 tdTestSessionEx([
2353 tdStepSessionSetEnv('', 'FOO', vbox.ComError.E_INVALIDARG),
2354 tdStepSessionCheckEnv(),
2355 tdStepRequireMinimumApiVer(5.0), # 4.3 is too relaxed checking input!
2356 tdStepSessionBulkEnv(['', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2357 tdStepSessionCheckEnv(),
2358 tdStepSessionSetEnv('FOO=', 'BAR', vbox.ComError.E_INVALIDARG),
2359 tdStepSessionCheckEnv(),
2360 ]),
2361 # A bit more weird keys/values.
2362 tdTestSessionEx([ tdStepSessionSetEnv('$$$', ''),
2363 tdStepSessionCheckEnv([ '$$$=',]), ]),
2364 tdTestSessionEx([ tdStepSessionSetEnv('$$$', '%%%'),
2365 tdStepSessionCheckEnv([ '$$$=%%%',]),
2366 ]),
2367 tdTestSessionEx([ tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2368 tdStepSessionSetEnv(u'ß$%ß&', ''),
2369 tdStepSessionCheckEnv([ u'ß$%ß&=',]),
2370 ]),
2371 # Misc stuff.
2372 tdTestSessionEx([ tdStepSessionSetEnv('FOO', ''),
2373 tdStepSessionCheckEnv(['FOO=',]),
2374 ]),
2375 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2376 tdStepSessionCheckEnv(['FOO=BAR',])
2377 ],),
2378 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2379 tdStepSessionSetEnv('BAR', 'BAZ'),
2380 tdStepSessionCheckEnv([ 'FOO=BAR', 'BAR=BAZ',]),
2381 ]),
2382 ];
2383 # Leading '=' in the name is okay for windows guests in 6.1 and later (for driver letter CWDs).
2384 if (self.oTstDrv.fpApiVer < 6.1 and self.oTstDrv.fpApiVer >= 5.0) or not oTestVm.isWindows():
2385 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=', '===', vbox.ComError.E_INVALIDARG),
2386 tdStepSessionCheckEnv(),
2387 tdStepSessionSetEnv('=FOO', 'BAR', vbox.ComError.E_INVALIDARG),
2388 tdStepSessionCheckEnv(),
2389 tdStepSessionBulkEnv(['=', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2390 tdStepSessionCheckEnv(),
2391 tdStepSessionBulkEnv(['=FOO', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2392 tdStepSessionCheckEnv(),
2393 tdStepSessionBulkEnv(['=D:=D:/tmp', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2394 tdStepSessionCheckEnv(),
2395 tdStepSessionSetEnv('=D:', 'D:/temp', vbox.ComError.E_INVALIDARG),
2396 tdStepSessionCheckEnv(),
2397 ]));
2398 elif self.oTstDrv.fpApiVer >= 6.1 and oTestVm.isWindows():
2399 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=D:', 'D:/tmp'),
2400 tdStepSessionCheckEnv(['=D:=D:/tmp',]),
2401 tdStepSessionBulkEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2402 tdStepSessionCheckEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2403 tdStepSessionUnsetEnv('=D:'),
2404 tdStepSessionCheckEnv(['=D:', '=FOO', 'foo=bar']),
2405 ]));
2406
2407 return tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession, oTestVm, 'SessionEnv');
2408
2409 def testGuestCtrlSession(self, oSession, oTxsSession, oTestVm):
2410 """
2411 Tests the guest session handling.
2412 """
2413
2414 #
2415 # Tests:
2416 #
2417 atTests = [
2418 # Invalid parameters.
2419 [ tdTestSession(sUser = ''), tdTestResultSession() ],
2420 # User account without a passwort - forbidden.
2421 [ tdTestSession(sPassword = "" ), tdTestResultSession() ],
2422 # Various wrong credentials.
2423 # Note! Only windows cares about sDomain, the other guests ignores it.
2424 # Note! On Guest Additions < 4.3 this always succeeds because these don't
2425 # support creating dedicated sessions. Instead, guest process creation
2426 # then will fail. See note below.
2427 [ tdTestSession(sPassword = 'bar'), tdTestResultSession() ],
2428 [ tdTestSession(sUser = 'foo', sPassword = 'bar'), tdTestResultSession() ],
2429 [ tdTestSession(sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2430 [ tdTestSession(sUser = 'foo', sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2431 ];
2432 if oTestVm.isWindows(): # domain is ignored elsewhere.
2433 atTests.append([ tdTestSession(sDomain = 'boo'), tdTestResultSession() ]);
2434
2435 # Finally, correct credentials.
2436 atTests.append([ tdTestSession(), tdTestResultSession(fRc = True, cNumSessions = 1) ]);
2437
2438 #
2439 # Run the tests.
2440 #
2441 fRc = True;
2442 for (i, tTest) in enumerate(atTests):
2443 oCurTest = tTest[0] # type: tdTestSession
2444 oCurRes = tTest[1] # type: tdTestResult
2445
2446 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2447 reporter.log('Testing #%d, user="%s", sPassword="%s", sDomain="%s" ...'
2448 % (i, oCurTest.oCreds.sUser, oCurTest.oCreds.sPassword, oCurTest.oCreds.sDomain));
2449 sCurGuestSessionName = 'testGuestCtrlSession: Test #%d' % (i,);
2450 fRc2, oCurGuestSession = oCurTest.createSession(sCurGuestSessionName, fIsError = oCurRes.fRc);
2451
2452 # See note about < 4.3 Guest Additions above.
2453 uProtocolVersion = 2;
2454 if oCurGuestSession is not None:
2455 try:
2456 uProtocolVersion = oCurGuestSession.protocolVersion;
2457 except:
2458 fRc = reporter.errorXcpt('Test #%d' % (i,));
2459
2460 if uProtocolVersion >= 2 and fRc2 is not oCurRes.fRc:
2461 fRc = reporter.error('Test #%d failed: Session creation failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
2462
2463 if fRc2 and oCurGuestSession is None:
2464 fRc = reporter.error('Test #%d failed: no session object' % (i,));
2465 fRc2 = False;
2466
2467 if fRc2:
2468 if uProtocolVersion >= 2: # For Guest Additions < 4.3 getSessionCount() always will return 1.
2469 cCurSessions = oCurTest.getSessionCount(self.oTstDrv.oVBoxMgr);
2470 if cCurSessions != oCurRes.cNumSessions:
2471 fRc = reporter.error('Test #%d failed: Session count does not match: Got %d, expected %d'
2472 % (i, cCurSessions, oCurRes.cNumSessions));
2473 try:
2474 sObjName = oCurGuestSession.name;
2475 except:
2476 fRc = reporter.errorXcpt('Test #%d' % (i,));
2477 else:
2478 if sObjName != sCurGuestSessionName:
2479 fRc = reporter.error('Test #%d failed: Session name does not match: Got "%s", expected "%s"'
2480 % (i, sObjName, sCurGuestSessionName));
2481 fRc2 = oCurTest.closeSession();
2482 if fRc2 is False:
2483 fRc = reporter.error('Test #%d failed: Session could not be closed' % (i,));
2484
2485 if fRc is False:
2486 return (False, oTxsSession);
2487
2488 #
2489 # Multiple sessions.
2490 #
2491 cMaxGuestSessions = 31; # Maximum number of concurrent guest session allowed.
2492 # Actually, this is 32, but we don't test session 0.
2493 aoMultiSessions = {};
2494 reporter.log2('Opening multiple guest tsessions at once ...');
2495 for i in xrange(cMaxGuestSessions + 1):
2496 aoMultiSessions[i] = tdTestSession(sSessionName = 'MultiSession #%d' % (i,));
2497 aoMultiSessions[i].setEnvironment(oSession, oTxsSession, oTestVm);
2498
2499 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2500 reporter.log2('MultiSession test #%d count is %d' % (i, cCurSessions));
2501 if cCurSessions != i:
2502 return (reporter.error('MultiSession count is %d, expected %d' % (cCurSessions, i)), oTxsSession);
2503 fRc2, _ = aoMultiSessions[i].createSession('MultiSession #%d' % (i,), i < cMaxGuestSessions);
2504 if fRc2 is not True:
2505 if i < cMaxGuestSessions:
2506 return (reporter.error('MultiSession #%d test failed' % (i,)), oTxsSession);
2507 reporter.log('MultiSession #%d exceeded concurrent guest session count, good' % (i,));
2508 break;
2509
2510 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2511 if cCurSessions is not cMaxGuestSessions:
2512 return (reporter.error('Final session count %d, expected %d ' % (cCurSessions, cMaxGuestSessions,)), oTxsSession);
2513
2514 reporter.log2('Closing MultiSessions ...');
2515 for i in xrange(cMaxGuestSessions):
2516 # Close this session:
2517 oClosedGuestSession = aoMultiSessions[i].oGuestSession;
2518 fRc2 = aoMultiSessions[i].closeSession();
2519 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr)
2520 reporter.log2('MultiSession #%d count is %d' % (i, cCurSessions,));
2521 if fRc2 is False:
2522 fRc = reporter.error('Closing MultiSession #%d failed' % (i,));
2523 elif cCurSessions != cMaxGuestSessions - (i + 1):
2524 fRc = reporter.error('Expected %d session after closing #%d, got %d instead'
2525 % (cMaxGuestSessions - (i + 1), cCurSessions, i,));
2526 assert aoMultiSessions[i].oGuestSession is None or not fRc2;
2527 ## @todo any way to check that the session is closed other than the 'sessions' attribute?
2528
2529 # Try check that none of the remaining sessions got closed.
2530 try:
2531 aoGuestSessions = self.oTstDrv.oVBoxMgr.getArray(atTests[0][0].oGuest, 'sessions');
2532 except:
2533 return (reporter.errorXcpt('i=%d/%d' % (i, cMaxGuestSessions,)), oTxsSession);
2534 if oClosedGuestSession in aoGuestSessions:
2535 fRc = reporter.error('i=%d/%d: %s should not be in %s'
2536 % (i, cMaxGuestSessions, oClosedGuestSession, aoGuestSessions));
2537 if i + 1 < cMaxGuestSessions: # Not sure what xrange(2,2) does...
2538 for j in xrange(i + 1, cMaxGuestSessions):
2539 if aoMultiSessions[j].oGuestSession not in aoGuestSessions:
2540 fRc = reporter.error('i=%d/j=%d/%d: %s should be in %s'
2541 % (i, j, cMaxGuestSessions, aoMultiSessions[j].oGuestSession, aoGuestSessions));
2542 ## @todo any way to check that they work?
2543
2544 ## @todo Test session timeouts.
2545
2546 return (fRc, oTxsSession);
2547
2548 def testGuestCtrlSessionFileRefs(self, oSession, oTxsSession, oTestVm):
2549 """
2550 Tests the guest session file reference handling.
2551 """
2552
2553 # Find a file to play around with:
2554 sFile = self.getGuestSystemFileForReading(oTestVm);
2555
2556 # Use credential defaults.
2557 oCreds = tdCtxCreds();
2558 oCreds.applyDefaultsIfNotSet(oTestVm);
2559
2560 # Number of stale guest files to create.
2561 cStaleFiles = 10;
2562
2563 #
2564 # Start a session.
2565 #
2566 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2567 try:
2568 oGuest = oSession.o.console.guest;
2569 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionFileRefs");
2570 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2571 except:
2572 return (reporter.errorXcpt(), oTxsSession);
2573
2574 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2575 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2576 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2577 reporter.log('Session successfully started');
2578
2579 #
2580 # Open guest files and "forget" them (stale entries).
2581 # For them we don't have any references anymore intentionally.
2582 #
2583 reporter.log2('Opening stale files');
2584 fRc = True;
2585 for i in xrange(0, cStaleFiles):
2586 try:
2587 if self.oTstDrv.fpApiVer >= 5.0:
2588 oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly, vboxcon.FileOpenAction_OpenExisting, 0);
2589 else:
2590 oGuestSession.fileOpen(sFile, "r", "oe", 0);
2591 # Note: Use a timeout in the call above for not letting the stale processes
2592 # hanging around forever. This can happen if the installed Guest Additions
2593 # do not support terminating guest processes.
2594 except:
2595 fRc = reporter.errorXcpt('Opening stale file #%d failed:' % (i,));
2596 break;
2597
2598 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2599 except: fRc = reporter.errorXcpt();
2600 else:
2601 if cFiles != cStaleFiles:
2602 fRc = reporter.error('Got %d stale files, expected %d' % (cFiles, cStaleFiles));
2603
2604 if fRc is True:
2605 #
2606 # Open non-stale files and close them again.
2607 #
2608 reporter.log2('Opening non-stale files');
2609 aoFiles = [];
2610 for i in xrange(0, cStaleFiles):
2611 try:
2612 if self.oTstDrv.fpApiVer >= 5.0:
2613 oCurFile = oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly,
2614 vboxcon.FileOpenAction_OpenExisting, 0);
2615 else:
2616 oCurFile = oGuestSession.fileOpen(sFile, "r", "oe", 0);
2617 aoFiles.append(oCurFile);
2618 except:
2619 fRc = reporter.errorXcpt('Opening non-stale file #%d failed:' % (i,));
2620 break;
2621
2622 # Check the count.
2623 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2624 except: fRc = reporter.errorXcpt();
2625 else:
2626 if cFiles != cStaleFiles * 2:
2627 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles * 2));
2628
2629 # Close them.
2630 reporter.log2('Closing all non-stale files again ...');
2631 for i, oFile in enumerate(aoFiles):
2632 try:
2633 oFile.close();
2634 except:
2635 fRc = reporter.errorXcpt('Closing non-stale file #%d failed:' % (i,));
2636
2637 # Check the count again.
2638 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2639 except: fRc = reporter.errorXcpt();
2640 # Here we count the stale files (that is, files we don't have a reference
2641 # anymore for) and the opened and then closed non-stale files (that we still keep
2642 # a reference in aoFiles[] for).
2643 if cFiles != cStaleFiles:
2644 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles));
2645
2646 #
2647 # Check that all (referenced) non-stale files are now in the "closed" state.
2648 #
2649 reporter.log2('Checking statuses of all non-stale files ...');
2650 for i, oFile in enumerate(aoFiles):
2651 try:
2652 eFileStatus = aoFiles[i].status;
2653 except:
2654 fRc = reporter.errorXcpt('Checking status of file #%d failed:' % (i,));
2655 else:
2656 if eFileStatus != vboxcon.FileStatus_Closed:
2657 fRc = reporter.error('Non-stale file #%d has status %d, expected %d'
2658 % (i, eFileStatus, vboxcon.FileStatus_Closed));
2659
2660 if fRc is True:
2661 reporter.log2('All non-stale files closed');
2662
2663 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2664 except: fRc = reporter.errorXcpt();
2665 else: reporter.log2('Final guest session file count: %d' % (cFiles,));
2666
2667 #
2668 # Now try to close the session and see what happens.
2669 # Note! Session closing is why we've been doing all the 'if fRc is True' stuff above rather than returning.
2670 #
2671 reporter.log2('Closing guest session ...');
2672 try:
2673 oGuestSession.close();
2674 except:
2675 fRc = reporter.errorXcpt('Testing for stale processes failed:');
2676
2677 return (fRc, oTxsSession);
2678
2679 #def testGuestCtrlSessionDirRefs(self, oSession, oTxsSession, oTestVm):
2680 # """
2681 # Tests the guest session directory reference handling.
2682 # """
2683
2684 # fRc = True;
2685 # return (fRc, oTxsSession);
2686
2687 def testGuestCtrlSessionProcRefs(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2688 """
2689 Tests the guest session process reference handling.
2690 """
2691
2692 sCmd = self.getGuestSystemShell(oTestVm);
2693 asArgs = [sCmd,];
2694
2695 # Use credential defaults.
2696 oCreds = tdCtxCreds();
2697 oCreds.applyDefaultsIfNotSet(oTestVm);
2698
2699 # Number of stale guest processes to create.
2700 cStaleProcs = 10;
2701
2702 #
2703 # Start a session.
2704 #
2705 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2706 try:
2707 oGuest = oSession.o.console.guest;
2708 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionProcRefs");
2709 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2710 except:
2711 return (reporter.errorXcpt(), oTxsSession);
2712
2713 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2714 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2715 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2716 reporter.log('Session successfully started');
2717
2718 #
2719 # Fire off forever-running processes and "forget" them (stale entries).
2720 # For them we don't have any references anymore intentionally.
2721 #
2722 reporter.log2('Starting stale processes...');
2723 fRc = True;
2724 for i in xrange(0, cStaleProcs):
2725 try:
2726 oGuestSession.processCreate(sCmd,
2727 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:], [],
2728 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], 30 * 1000);
2729 # Note: Use a timeout in the call above for not letting the stale processes
2730 # hanging around forever. This can happen if the installed Guest Additions
2731 # do not support terminating guest processes.
2732 except:
2733 fRc = reporter.errorXcpt('Creating stale process #%d failed:' % (i,));
2734 break;
2735
2736 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2737 except: fRc = reporter.errorXcpt();
2738 else:
2739 if cProcesses != cStaleProcs:
2740 fRc = reporter.error('Got %d stale processes, expected %d' % (cProcesses, cStaleProcs));
2741
2742 if fRc is True:
2743 #
2744 # Fire off non-stale processes and wait for termination.
2745 #
2746 if oTestVm.isWindows() or oTestVm.isOS2():
2747 asArgs = [ sCmd, '/C', 'dir', '/S', self.getGuestSystemDir(oTestVm), ];
2748 else:
2749 asArgs = [ sCmd, '-c', 'ls -la ' + self.getGuestSystemDir(oTestVm), ];
2750 reporter.log2('Starting non-stale processes...');
2751 aoProcesses = [];
2752 for i in xrange(0, cStaleProcs):
2753 try:
2754 oCurProc = oGuestSession.processCreate(sCmd, asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2755 [], [], 0); # Infinite timeout.
2756 aoProcesses.append(oCurProc);
2757 except:
2758 fRc = reporter.errorXcpt('Creating non-stale process #%d failed:' % (i,));
2759 break;
2760
2761 reporter.log2('Waiting for non-stale processes to terminate...');
2762 for i, oProcess in enumerate(aoProcesses):
2763 try:
2764 eWaitResult = oProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 120 * 1000);
2765 eProcessStatus = oProcess.status;
2766 except:
2767 fRc = reporter.errorXcpt('Waiting for non-stale process #%d failed:' % (i,));
2768 else:
2769 if eProcessStatus != vboxcon.ProcessStatus_TerminatedNormally:
2770 fRc = reporter.error('Waiting for non-stale processes #%d resulted in status %d, expected %d (wr=%d)'
2771 % (i, eProcessStatus, vboxcon.ProcessStatus_TerminatedNormally, eWaitResult));
2772
2773 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2774 except: fRc = reporter.errorXcpt();
2775 else:
2776 # Here we count the stale processes (that is, processes we don't have a reference
2777 # anymore for) and the started + terminated non-stale processes (that we still keep
2778 # a reference in aoProcesses[] for).
2779 if cProcesses != (cStaleProcs * 2):
2780 fRc = reporter.error('Got %d total processes, expected %d' % (cProcesses, cStaleProcs));
2781
2782 if fRc is True:
2783 reporter.log2('All non-stale processes terminated');
2784
2785 #
2786 # Fire off non-stale blocking processes which are terminated via terminate().
2787 #
2788 if oTestVm.isWindows() or oTestVm.isOS2():
2789 asArgs = [ sCmd, '/C', 'pause'];
2790 else:
2791 asArgs = [ sCmd ];
2792 reporter.log2('Starting blocking processes...');
2793 aoProcesses = [];
2794 for i in xrange(0, cStaleProcs):
2795 try:
2796 oCurProc = oGuestSession.processCreate(sCmd, asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2797 [], [], 30 * 1000);
2798 # Note: Use a timeout in the call above for not letting the stale processes
2799 # hanging around forever. This can happen if the installed Guest Additions
2800 # do not support terminating guest processes.
2801 aoProcesses.append(oCurProc);
2802 except:
2803 fRc = reporter.errorXcpt('Creating non-stale blocking process #%d failed:' % (i,));
2804 break;
2805
2806 reporter.log2('Terminating blocking processes...');
2807 for i, oProcess in enumerate(aoProcesses):
2808 try:
2809 oProcess.terminate();
2810 except: # Termination might not be supported, just skip and log it.
2811 reporter.logXcpt('Termination of blocking process #%d failed, skipped:' % (i,));
2812
2813 # There still should be 20 processes because we terminated the 10 newest ones.
2814 try: cProcesses = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2815 except: fRc = reporter.errorXcpt();
2816 else:
2817 if cProcesses != (cStaleProcs * 2):
2818 fRc = reporter.error('Got %d total processes, expected %d' % (cProcesses, cStaleProcs));
2819 reporter.log2('Final guest session processes count: %d' % (cProcesses,));
2820
2821 #
2822 # Now try to close the session and see what happens.
2823 #
2824 reporter.log2('Closing guest session ...');
2825 try:
2826 oGuestSession.close();
2827 except:
2828 fRc = reporter.errorXcpt('Testing for stale processes failed:');
2829
2830 return (fRc, oTxsSession);
2831
2832 def testGuestCtrlExec(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
2833 """
2834 Tests the basic execution feature.
2835 """
2836
2837 # Paths:
2838 sVBoxControl = None; ## @todo Get path of installed Guest Additions. Later.
2839 sShell = self.getGuestSystemShell(oTestVm);
2840 sShellOpt = '/C' if oTestVm.isWindows() or oTestVm.isOS2() else '-c';
2841 sSystemDir = self.getGuestSystemDir(oTestVm);
2842 sFileForReading = self.getGuestSystemFileForReading(oTestVm);
2843 if oTestVm.isWindows() or oTestVm.isOS2():
2844 sImageOut = self.getGuestSystemShell(oTestVm);
2845 if oTestVm.isWindows():
2846 sVBoxControl = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe";
2847 else:
2848 sImageOut = "/bin/ls";
2849 if oTestVm.isLinux(): ## @todo check solaris and darwin.
2850 sVBoxControl = "/usr/bin/VBoxControl"; # Symlink
2851
2852 # Use credential defaults.
2853 oCreds = tdCtxCreds();
2854 oCreds.applyDefaultsIfNotSet(oTestVm);
2855
2856 atInvalid = [
2857 # Invalid parameters.
2858 [ tdTestExec(), tdTestResultExec() ],
2859 # Non-existent / invalid image.
2860 [ tdTestExec(sCmd = "non-existent"), tdTestResultExec() ],
2861 [ tdTestExec(sCmd = "non-existent2"), tdTestResultExec() ],
2862 # Use an invalid format string.
2863 [ tdTestExec(sCmd = "%$%%%&"), tdTestResultExec() ],
2864 # More stuff.
2865 [ tdTestExec(sCmd = u"ƒ‰‹ˆ÷‹¸"), tdTestResultExec() ],
2866 [ tdTestExec(sCmd = "???://!!!"), tdTestResultExec() ],
2867 [ tdTestExec(sCmd = "<>!\\"), tdTestResultExec() ],
2868 # Enable as soon as ERROR_BAD_DEVICE is implemented.
2869 #[ tdTestExec(sCmd = "CON", tdTestResultExec() ],
2870 ];
2871
2872 atExec = [];
2873 if oTestVm.isWindows() or oTestVm.isOS2():
2874 atExec += [
2875 # Basic execution.
2876 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2877 tdTestResultExec(fRc = True) ],
2878 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sFileForReading ]),
2879 tdTestResultExec(fRc = True) ],
2880 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir + '\\nonexist.dll' ]),
2881 tdTestResultExec(fRc = True, iExitCode = 1) ],
2882 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ]),
2883 tdTestResultExec(fRc = True, iExitCode = 1) ],
2884 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
2885 tdTestResultExec(fRc = True, iExitCode = 1) ],
2886 # StdOut.
2887 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2888 tdTestResultExec(fRc = True) ],
2889 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ]),
2890 tdTestResultExec(fRc = True, iExitCode = 1) ],
2891 # StdErr.
2892 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2893 tdTestResultExec(fRc = True) ],
2894 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ]),
2895 tdTestResultExec(fRc = True, iExitCode = 1) ],
2896 # StdOut + StdErr.
2897 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
2898 tdTestResultExec(fRc = True) ],
2899 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ]),
2900 tdTestResultExec(fRc = True, iExitCode = 1) ],
2901 ];
2902 # atExec.extend([
2903 # FIXME: Failing tests.
2904 # Environment variables.
2905 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
2906 # tdTestResultExec(fRc = True, iExitCode = 1) ]
2907 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
2908 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2909 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
2910 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2911 # aEnv = [ 'TEST_FOO=BAR' ],
2912 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2913 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
2914 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2915 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
2916 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2917 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
2918
2919 ## @todo Create some files (or get files) we know the output size of to validate output length!
2920 ## @todo Add task which gets killed at some random time while letting the guest output something.
2921 #];
2922 else:
2923 atExec += [
2924 # Basic execution.
2925 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '-R', sSystemDir ]),
2926 tdTestResultExec(fRc = True) ],
2927 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sFileForReading ]),
2928 tdTestResultExec(fRc = True) ],
2929 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '--wrong-parameter' ]),
2930 tdTestResultExec(fRc = True, iExitCode = 2) ],
2931 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/non/existent' ]),
2932 tdTestResultExec(fRc = True, iExitCode = 2) ],
2933 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
2934 tdTestResultExec(fRc = True, iExitCode = 127) ],
2935 # StdOut.
2936 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2937 tdTestResultExec(fRc = True) ],
2938 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdout-non-existing' ]),
2939 tdTestResultExec(fRc = True, iExitCode = 2) ],
2940 # StdErr.
2941 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2942 tdTestResultExec(fRc = True) ],
2943 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stderr-non-existing' ]),
2944 tdTestResultExec(fRc = True, iExitCode = 2) ],
2945 # StdOut + StdErr.
2946 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
2947 tdTestResultExec(fRc = True) ],
2948 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdouterr-non-existing' ]),
2949 tdTestResultExec(fRc = True, iExitCode = 2) ],
2950 ];
2951 # atExec.extend([
2952 # FIXME: Failing tests.
2953 # Environment variables.
2954 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
2955 # tdTestResultExec(fRc = True, iExitCode = 1) ]
2956 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
2957 #
2958 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2959 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
2960 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2961 # aEnv = [ 'TEST_FOO=BAR' ],
2962 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2963 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
2964 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
2965 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
2966 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2967 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
2968
2969 ## @todo Create some files (or get files) we know the output size of to validate output length!
2970 ## @todo Add task which gets killed at some random time while letting the guest output something.
2971 #];
2972
2973 #
2974 for iExitCode in xrange(0, 127):
2975 atExec.append([ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'exit %s' % iExitCode ]),
2976 tdTestResultExec(fRc = True, iExitCode = iExitCode) ]);
2977
2978 if sVBoxControl:
2979 # Paths with spaces on windows.
2980 atExec.append([ tdTestExec(sCmd = sVBoxControl, asArgs = [ sVBoxControl, 'version' ],
2981 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
2982 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
2983 tdTestResultExec(fRc = True) ]);
2984
2985 # Build up the final test array for the first batch.
2986 atTests = atInvalid + atExec;
2987
2988 #
2989 # First batch: One session per guest process.
2990 #
2991 reporter.log('One session per guest process ...');
2992 fRc = True;
2993 for (i, tTest) in enumerate(atTests):
2994 oCurTest = tTest[0] # type: tdTestExec
2995 oCurRes = tTest[1] # type: tdTestResultExec
2996 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2997 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlExec: Test #%d' % (i,));
2998 if fRc2 is not True:
2999 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3000 break;
3001 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession) and fRc;
3002 fRc = oCurTest.closeSession() and fRc;
3003
3004 reporter.log('Execution of all tests done, checking for stale sessions');
3005
3006 # No sessions left?
3007 try:
3008 aSessions = self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions');
3009 except:
3010 fRc = reporter.errorXcpt();
3011 else:
3012 cSessions = len(aSessions);
3013 if cSessions != 0:
3014 fRc = reporter.error('Found %d stale session(s), expected 0:' % (cSessions,));
3015 for (i, aSession) in enumerate(aSessions):
3016 try: reporter.log(' Stale session #%d ("%s")' % (aSession.id, aSession.name));
3017 except: reporter.errorXcpt();
3018
3019 if fRc is not True:
3020 return (fRc, oTxsSession);
3021
3022 reporter.log('Now using one guest session for all tests ...');
3023
3024 #
3025 # Second batch: One session for *all* guest processes.
3026 #
3027
3028 # Create session.
3029 reporter.log('Creating session for all tests ...');
3030 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
3031 try:
3032 oGuest = oSession.o.console.guest;
3033 oCurGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain,
3034 'testGuestCtrlExec: One session for all tests');
3035 except:
3036 return (reporter.errorXcpt(), oTxsSession);
3037
3038 try:
3039 eWaitResult = oCurGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3040 except:
3041 fRc = reporter.errorXcpt('Waiting for guest session to start failed:');
3042 else:
3043 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3044 fRc = reporter.error('Session did not start successfully, returned wait result: %d' % (eWaitResult,));
3045 else:
3046 reporter.log('Session successfully started');
3047
3048 # Do the tests within this session.
3049 for (i, tTest) in enumerate(atTests):
3050 oCurTest = tTest[0] # type: tdTestExec
3051 oCurRes = tTest[1] # type: tdTestResultExec
3052
3053 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3054 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession);
3055 if fRc is False:
3056 break;
3057
3058 # Close the session.
3059 reporter.log2('Closing guest session ...');
3060 try:
3061 oCurGuestSession.close();
3062 oCurGuestSession = None;
3063 except:
3064 fRc = reporter.errorXcpt('Closing guest session failed:');
3065
3066 # No sessions left?
3067 reporter.log('Execution of all tests done, checking for stale sessions again');
3068 try: cSessions = len(self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions'));
3069 except: fRc = reporter.errorXcpt();
3070 else:
3071 if cSessions != 0:
3072 fRc = reporter.error('Found %d stale session(s), expected 0' % (cSessions,));
3073 return (fRc, oTxsSession);
3074
3075 def threadForTestGuestCtrlSessionReboot(self, oGuestProcess):
3076 """
3077 Thread routine which waits for the stale guest process getting terminated (or some error)
3078 while the main test routine reboots the guest. It then compares the expected guest process result
3079 and logs an error if appropriate.
3080 """
3081 reporter.log('Waiting for process to get terminated at reboot ...');
3082 try:
3083 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate ], 5 * 60 * 1000);
3084 except:
3085 return reporter.errorXcpt('waitForArray failed');
3086 try:
3087 eStatus = oGuestProcess.status
3088 except:
3089 return reporter.errorXcpt('failed to get status (wait result %d)' % (eWaitResult,));
3090
3091 if eWaitResult == vboxcon.ProcessWaitResult_Terminate and eStatus == vboxcon.ProcessStatus_Down:
3092 reporter.log('Stale process was correctly terminated (status: down)');
3093 return True;
3094
3095 return reporter.error('Process wait across reboot failed: eWaitResult=%d, expected %d; eStatus=%d, expected %d'
3096 % (eWaitResult, vboxcon.ProcessWaitResult_Terminate, eStatus, vboxcon.ProcessStatus_Down,));
3097
3098 def testGuestCtrlSessionReboot(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3099 """
3100 Tests guest object notifications when a guest gets rebooted / shutdown.
3101
3102 These notifications gets sent from the guest sessions in order to make API clients
3103 aware of guest session changes.
3104
3105 To test that we create a stale guest process and trigger a reboot of the guest.
3106 """
3107
3108 ## @todo backport fixes to 6.0 and maybe 5.2
3109 if self.oTstDrv.fpApiVer <= 6.0:
3110 reporter.log('Skipping: Required fixes not yet backported!');
3111 return None;
3112
3113 # Use credential defaults.
3114 oCreds = tdCtxCreds();
3115 oCreds.applyDefaultsIfNotSet(oTestVm);
3116
3117 fRc = True;
3118
3119 #
3120 # Start a session.
3121 #
3122 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3123 try:
3124 oGuest = oSession.o.console.guest;
3125 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionReboot");
3126 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3127 except:
3128 return (reporter.errorXcpt(), oTxsSession);
3129
3130 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3131 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3132 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3133 reporter.log('Session successfully started');
3134
3135 #
3136 # Create a process.
3137 #
3138 sImage = self.getGuestSystemShell(oTestVm);
3139 asArgs = [ sImage, ];
3140 aEnv = [];
3141 afFlags = [];
3142 try:
3143 oGuestProcess = oGuestSession.processCreate(sImage,
3144 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:], aEnv, afFlags,
3145 30 * 1000);
3146 except:
3147 fRc = reporter.error('Failed to start shell process (%s)' % (sImage,));
3148 else:
3149 try:
3150 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3151 except:
3152 fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3153 else:
3154 # Check the result and state:
3155 try: eStatus = oGuestProcess.status;
3156 except: fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3157 else:
3158 reporter.log2('Starting process wait result returned: %d; Process status is: %d' % (eWaitResult, eStatus,));
3159 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3160 fRc = reporter.error('wait for ProcessWaitForFlag_Start failed: %d, expected %d (Start)'
3161 % (eWaitResult, vboxcon.ProcessWaitResult_Start,));
3162 elif eStatus != vboxcon.ProcessStatus_Started:
3163 fRc = reporter.error('Unexpected process status after startup: %d, wanted %d (Started)'
3164 % (eStatus, vboxcon.ProcessStatus_Started,));
3165 else:
3166 # Create a thread that waits on the process to terminate
3167 reporter.log('Creating reboot thread ...');
3168 oThreadReboot = threading.Thread(target = self.threadForTestGuestCtrlSessionReboot,
3169 args = (oGuestProcess,),
3170 name = ('threadForTestGuestCtrlSessionReboot'));
3171 oThreadReboot.setDaemon(True);
3172 oThreadReboot.start();
3173
3174 # Not sure why this fudge is needed...
3175 reporter.log('5 second wait fudge before triggering reboot ...');
3176 self.oTstDrv.sleep(5);
3177
3178 # Do the reboot.
3179 reporter.log('Rebooting guest and reconnecting TXS ...');
3180 (oSession, oTxsSession) = self.oTstDrv.txsRebootAndReconnectViaTcp(oSession, oTxsSession,
3181 cMsTimeout = 3 * 60000);
3182 if not oSession or not oTxsSession:
3183 try: oGuestProcess.terminate();
3184 except: reporter.logXcpt();
3185 fRc = False;
3186
3187 reporter.log('Waiting for thread to finish ...');
3188 oThreadReboot.join();
3189
3190 #
3191 # Try make sure we don't leave with a stale process on failure.
3192 #
3193 try: oGuestProcess.terminate();
3194 except: reporter.logXcpt();
3195
3196 #
3197 # Close the session.
3198 #
3199 reporter.log2('Closing guest session ...');
3200 try:
3201 oGuestSession.close();
3202 except:
3203 fRc = reporter.errorXcpt();
3204
3205 return (fRc, oTxsSession);
3206
3207 def testGuestCtrlExecTimeout(self, oSession, oTxsSession, oTestVm):
3208 """
3209 Tests handling of timeouts of started guest processes.
3210 """
3211
3212 sShell = self.getGuestSystemShell(oTestVm);
3213
3214 # Use credential defaults.
3215 oCreds = tdCtxCreds();
3216 oCreds.applyDefaultsIfNotSet(oTestVm);
3217
3218 #
3219 # Create a session.
3220 #
3221 try:
3222 oGuest = oSession.o.console.guest;
3223 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlExecTimeout");
3224 eWaitResult = oGuestSession.waitForArray([ vboxcon.GuestSessionWaitForFlag_Start, ], 30 * 1000);
3225 except:
3226 return (reporter.errorXcpt(), oTxsSession);
3227
3228 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3229 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3230 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3231 reporter.log('Session successfully started');
3232
3233 #
3234 # Create a process which never terminates and should timeout when
3235 # waiting for termination.
3236 #
3237 fRc = True;
3238 try:
3239 oCurProcess = oGuestSession.processCreate(sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3240 [], [], 30 * 1000);
3241 except:
3242 fRc = reporter.errorXcpt();
3243 else:
3244 reporter.log('Waiting for process 1 being started ...');
3245 try:
3246 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3247 except:
3248 fRc = reporter.errorXcpt();
3249 else:
3250 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3251 fRc = reporter.error('Waiting for process 1 to start failed, got status %d' % (eWaitResult,));
3252 else:
3253 for msWait in (1, 32, 2000,):
3254 reporter.log('Waiting for process 1 to time out within %sms ...' % (msWait,));
3255 try:
3256 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], msWait);
3257 except:
3258 fRc = reporter.errorXcpt();
3259 break;
3260 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3261 fRc = reporter.error('Waiting for process 1 did not time out in %sms as expected: %d'
3262 % (msWait, eWaitResult,));
3263 break;
3264 reporter.log('Waiting for process 1 timed out in %u ms, good' % (msWait,));
3265
3266 try:
3267 oCurProcess.terminate();
3268 except:
3269 reporter.errorXcpt();
3270 oCurProcess = None;
3271
3272 #
3273 # Create another process that doesn't terminate, but which will be killed by VBoxService
3274 # because it ran out of execution time (3 seconds).
3275 #
3276 try:
3277 oCurProcess = oGuestSession.processCreate(sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3278 [], [], 3 * 1000);
3279 except:
3280 fRc = reporter.errorXcpt();
3281 else:
3282 reporter.log('Waiting for process 2 being started ...');
3283 try:
3284 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3285 except:
3286 fRc = reporter.errorXcpt();
3287 else:
3288 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3289 fRc = reporter.error('Waiting for process 2 to start failed, got status %d' % (eWaitResult,));
3290 else:
3291 reporter.log('Waiting for process 2 to get killed for running out of execution time ...');
3292 try:
3293 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 15 * 1000);
3294 except:
3295 fRc = reporter.errorXcpt();
3296 else:
3297 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3298 fRc = reporter.error('Waiting for process 2 did not time out when it should, got wait result %d'
3299 % (eWaitResult,));
3300 else:
3301 reporter.log('Waiting for process 2 did not time out, good: %s' % (eWaitResult,));
3302 try:
3303 eStatus = oCurProcess.status;
3304 except:
3305 fRc = reporter.errorXcpt();
3306 else:
3307 if eStatus != vboxcon.ProcessStatus_TimedOutKilled:
3308 fRc = reporter.error('Status of process 2 wrong; excepted %d, got %d'
3309 % (vboxcon.ProcessStatus_TimedOutKilled, eStatus));
3310 else:
3311 reporter.log('Status of process 2 is TimedOutKilled (%d) is it should be.'
3312 % (vboxcon.ProcessStatus_TimedOutKilled,));
3313 try:
3314 oCurProcess.terminate();
3315 except:
3316 reporter.logXcpt();
3317 oCurProcess = None;
3318
3319 #
3320 # Clean up the session.
3321 #
3322 try:
3323 oGuestSession.close();
3324 except:
3325 fRc = reporter.errorXcpt();
3326
3327 return (fRc, oTxsSession);
3328
3329 def testGuestCtrlDirCreate(self, oSession, oTxsSession, oTestVm):
3330 """
3331 Tests creation of guest directories.
3332 """
3333
3334 sScratch = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'testGuestCtrlDirCreate');
3335
3336 atTests = [
3337 # Invalid stuff.
3338 [ tdTestDirCreate(sDirectory = '' ), tdTestResultFailure() ],
3339 # More unusual stuff.
3340 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '.') ), tdTestResultFailure() ],
3341 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '..') ), tdTestResultFailure() ],
3342 [ tdTestDirCreate(sDirectory = '..' ), tdTestResultFailure() ],
3343 [ tdTestDirCreate(sDirectory = '../' ), tdTestResultFailure() ],
3344 [ tdTestDirCreate(sDirectory = '../../' ), tdTestResultFailure() ],
3345 [ tdTestDirCreate(sDirectory = '/' ), tdTestResultFailure() ],
3346 [ tdTestDirCreate(sDirectory = '/..' ), tdTestResultFailure() ],
3347 [ tdTestDirCreate(sDirectory = '/../' ), tdTestResultFailure() ],
3348 ];
3349 if oTestVm.isWindows() or oTestVm.isOS2():
3350 atTests.extend([
3351 [ tdTestDirCreate(sDirectory = 'C:\\' ), tdTestResultFailure() ],
3352 [ tdTestDirCreate(sDirectory = 'C:\\..' ), tdTestResultFailure() ],
3353 [ tdTestDirCreate(sDirectory = 'C:\\..\\' ), tdTestResultFailure() ],
3354 [ tdTestDirCreate(sDirectory = 'C:/' ), tdTestResultFailure() ],
3355 [ tdTestDirCreate(sDirectory = 'C:/.' ), tdTestResultFailure() ],
3356 [ tdTestDirCreate(sDirectory = 'C:/./' ), tdTestResultFailure() ],
3357 [ tdTestDirCreate(sDirectory = 'C:/..' ), tdTestResultFailure() ],
3358 [ tdTestDirCreate(sDirectory = 'C:/../' ), tdTestResultFailure() ],
3359 [ tdTestDirCreate(sDirectory = '\\\\uncrulez\\foo' ), tdTestResultFailure() ],
3360 ]);
3361 atTests.extend([
3362 # Existing directories and files.
3363 [ tdTestDirCreate(sDirectory = self.getGuestSystemDir(oTestVm) ), tdTestResultFailure() ],
3364 [ tdTestDirCreate(sDirectory = self.getGuestSystemShell(oTestVm) ), tdTestResultFailure() ],
3365 [ tdTestDirCreate(sDirectory = self.getGuestSystemFileForReading(oTestVm) ), tdTestResultFailure() ],
3366 # Creating directories.
3367 [ tdTestDirCreate(sDirectory = sScratch ), tdTestResultSuccess() ],
3368 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3369 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3370 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3371 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3372 # Long random names.
3373 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(36, 28))),
3374 tdTestResultSuccess() ],
3375 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(140, 116))),
3376 tdTestResultSuccess() ],
3377 # Too long names. ASSUMES a guests has a 255 filename length limitation.
3378 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3379 tdTestResultFailure() ],
3380 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3381 tdTestResultFailure() ],
3382 # Missing directory in path.
3383 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo1', 'bar') ), tdTestResultFailure() ],
3384 ]);
3385
3386 fRc = True;
3387 for (i, tTest) in enumerate(atTests):
3388 oCurTest = tTest[0] # type: tdTestDirCreate
3389 oCurRes = tTest[1] # type: tdTestResult
3390 reporter.log('Testing #%d, sDirectory="%s" ...' % (i, oCurTest.sDirectory));
3391
3392 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3393 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreate: Test #%d' % (i,));
3394 if fRc is False:
3395 return reporter.error('Test #%d failed: Could not create session' % (i,));
3396
3397 fRc = self.gctrlCreateDir(oCurTest, oCurRes, oCurGuestSession);
3398
3399 fRc = oCurTest.closeSession() and fRc;
3400 if fRc is False:
3401 fRc = reporter.error('Test #%d failed' % (i,));
3402
3403 return (fRc, oTxsSession);
3404
3405 def testGuestCtrlDirCreateTemp(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3406 """
3407 Tests creation of temporary directories.
3408 """
3409
3410 sSystemDir = self.getGuestSystemDir(oTestVm);
3411 atTests = [
3412 # Invalid stuff (template must have one or more trailin 'X'es (upper case only), or a cluster of three or more).
3413 [ tdTestDirCreateTemp(sDirectory = ''), tdTestResultFailure() ],
3414 [ tdTestDirCreateTemp(sDirectory = sSystemDir, fMode = 1234), tdTestResultFailure() ],
3415 [ tdTestDirCreateTemp(sTemplate = 'xXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3416 [ tdTestDirCreateTemp(sTemplate = 'xxx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3417 [ tdTestDirCreateTemp(sTemplate = 'XXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3418 [ tdTestDirCreateTemp(sTemplate = 'bar', sDirectory = 'whatever', fMode = 0o700), tdTestResultFailure() ],
3419 [ tdTestDirCreateTemp(sTemplate = 'foo', sDirectory = 'it is not used', fMode = 0o700), tdTestResultFailure() ],
3420 [ tdTestDirCreateTemp(sTemplate = 'X,so', sDirectory = 'pointless test', fMode = 0o700), tdTestResultFailure() ],
3421 # Non-existing stuff.
3422 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX',
3423 sDirectory = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'non', 'existing')),
3424 tdTestResultFailure() ],
3425 # Working stuff:
3426 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3427 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3428 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3429 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3430 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3431 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3432 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3433 ## @todo test fSecure and pass weird fMode values once these parameters are implemented in the API.
3434 ];
3435
3436 fRc = True;
3437 for (i, tTest) in enumerate(atTests):
3438 oCurTest = tTest[0] # type: tdTestDirCreateTemp
3439 oCurRes = tTest[1] # type: tdTestResult
3440 reporter.log('Testing #%d, sTemplate="%s", fMode=%#o, path="%s", secure="%s" ...' %
3441 (i, oCurTest.sTemplate, oCurTest.fMode, oCurTest.sDirectory, oCurTest.fSecure));
3442
3443 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3444 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreateTemp: Test #%d' % (i,));
3445 if fRc is False:
3446 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3447 break;
3448
3449 sDirTemp = '';
3450 try:
3451 sDirTemp = oCurGuestSession.directoryCreateTemp(oCurTest.sTemplate, oCurTest.fMode,
3452 oCurTest.sDirectory, oCurTest.fSecure);
3453 except:
3454 if oCurRes.fRc is True:
3455 fRc = reporter.errorXcpt('Creating temp directory "%s" failed:' % (oCurTest.sDirectory,));
3456 else:
3457 reporter.logXcpt('Creating temp directory "%s" failed expectedly, skipping:' % (oCurTest.sDirectory,));
3458 else:
3459 reporter.log2('Temporary directory is: "%s"' % (sDirTemp,));
3460 if not sDirTemp:
3461 fRc = reporter.error('Resulting directory is empty!');
3462 else:
3463 ## @todo This does not work for some unknown reason.
3464 #try:
3465 # if self.oTstDrv.fpApiVer >= 5.0:
3466 # fExists = oCurGuestSession.directoryExists(sDirTemp, False);
3467 # else:
3468 # fExists = oCurGuestSession.directoryExists(sDirTemp);
3469 #except:
3470 # fRc = reporter.errorXcpt('sDirTemp=%s' % (sDirTemp,));
3471 #else:
3472 # if fExists is not True:
3473 # fRc = reporter.error('Test #%d failed: Temporary directory "%s" does not exists (%s)'
3474 # % (i, sDirTemp, fExists));
3475 try:
3476 oFsObjInfo = oCurGuestSession.fsObjQueryInfo(sDirTemp, False);
3477 eType = oFsObjInfo.type;
3478 except:
3479 fRc = reporter.errorXcpt('sDirTemp="%s"' % (sDirTemp,));
3480 else:
3481 reporter.log2('%s: eType=%s (dir=%d)' % (sDirTemp, eType, vboxcon.FsObjType_Directory,));
3482 if eType != vboxcon.FsObjType_Directory:
3483 fRc = reporter.error('Temporary directory "%s" not created as a directory: eType=%d'
3484 % (sDirTemp, eType));
3485 fRc = oCurTest.closeSession() and fRc;
3486 return (fRc, oTxsSession);
3487
3488 def testGuestCtrlDirRead(self, oSession, oTxsSession, oTestVm):
3489 """
3490 Tests opening and reading (enumerating) guest directories.
3491 """
3492
3493 sSystemDir = self.getGuestSystemDir(oTestVm);
3494 atTests = [
3495 # Invalid stuff.
3496 [ tdTestDirRead(sDirectory = ''), tdTestResultDirRead() ],
3497 [ tdTestDirRead(sDirectory = sSystemDir, afFlags = [ 1234 ]), tdTestResultDirRead() ],
3498 [ tdTestDirRead(sDirectory = sSystemDir, sFilter = '*.foo'), tdTestResultDirRead() ],
3499 # Non-existing stuff.
3500 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'really-no-such-subdir')), tdTestResultDirRead() ],
3501 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'non', 'existing')), tdTestResultDirRead() ],
3502 ];
3503
3504 if oTestVm.isWindows() or oTestVm.isOS2():
3505 atTests.extend([
3506 # More unusual stuff.
3507 [ tdTestDirRead(sDirectory = 'z:\\'), tdTestResultDirRead() ],
3508 [ tdTestDirRead(sDirectory = '\\\\uncrulez\\foo'), tdTestResultDirRead() ],
3509 ]);
3510
3511 # Read the system directory (ASSUMES at least 5 files in it):
3512 # Windows 7+ has inaccessible system32/com/dmp directory that screws up this test, so skip it on windows:
3513 if not oTestVm.isWindows():
3514 atTests.append([ tdTestDirRead(sDirectory = sSystemDir),
3515 tdTestResultDirRead(fRc = True, cFiles = -5, cDirs = None) ]);
3516 ## @todo trailing slash
3517
3518 # Read from the test file set.
3519 atTests.extend([
3520 [ tdTestDirRead(sDirectory = self.oTestFiles.oEmptyDir.sPath),
3521 tdTestResultDirRead(fRc = True, cFiles = 0, cDirs = 0, cOthers = 0) ],
3522 [ tdTestDirRead(sDirectory = self.oTestFiles.oManyDir.sPath),
3523 tdTestResultDirRead(fRc = True, cFiles = len(self.oTestFiles.oManyDir.aoChildren), cDirs = 0, cOthers = 0) ],
3524 [ tdTestDirRead(sDirectory = self.oTestFiles.oTreeDir.sPath),
3525 tdTestResultDirRead(fRc = True, cFiles = self.oTestFiles.cTreeFiles, cDirs = self.oTestFiles.cTreeDirs,
3526 cOthers = self.oTestFiles.cTreeOthers) ],
3527 ]);
3528
3529
3530 fRc = True;
3531 for (i, tTest) in enumerate(atTests):
3532 oCurTest = tTest[0] # type: tdTestExec
3533 oCurRes = tTest[1] # type: tdTestResultDirRead
3534
3535 reporter.log('Testing #%d, dir="%s" ...' % (i, oCurTest.sDirectory));
3536 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3537 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: Test #%d' % (i,));
3538 if fRc is not True:
3539 break;
3540 (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc);
3541 fRc = oCurTest.closeSession() and fRc;
3542
3543 reporter.log2('Test #%d: Returned %d directories, %d files total' % (i, cDirs, cFiles));
3544 if fRc2 is oCurRes.fRc:
3545 if fRc2 is True:
3546 if oCurRes.cFiles is None:
3547 pass; # ignore
3548 elif oCurRes.cFiles >= 0 and cFiles != oCurRes.cFiles:
3549 fRc = reporter.error('Test #%d failed: Got %d files, expected %d' % (i, cFiles, oCurRes.cFiles));
3550 elif oCurRes.cFiles < 0 and cFiles < -oCurRes.cFiles:
3551 fRc = reporter.error('Test #%d failed: Got %d files, expected at least %d'
3552 % (i, cFiles, -oCurRes.cFiles));
3553 if oCurRes.cDirs is None:
3554 pass; # ignore
3555 elif oCurRes.cDirs >= 0 and cDirs != oCurRes.cDirs:
3556 fRc = reporter.error('Test #%d failed: Got %d directories, expected %d' % (i, cDirs, oCurRes.cDirs));
3557 elif oCurRes.cDirs < 0 and cDirs < -oCurRes.cDirs:
3558 fRc = reporter.error('Test #%d failed: Got %d directories, expected at least %d'
3559 % (i, cDirs, -oCurRes.cDirs));
3560 if oCurRes.cOthers is None:
3561 pass; # ignore
3562 elif oCurRes.cOthers >= 0 and cOthers != oCurRes.cOthers:
3563 fRc = reporter.error('Test #%d failed: Got %d other types, expected %d' % (i, cOthers, oCurRes.cOthers));
3564 elif oCurRes.cOthers < 0 and cOthers < -oCurRes.cOthers:
3565 fRc = reporter.error('Test #%d failed: Got %d other types, expected at least %d'
3566 % (i, cOthers, -oCurRes.cOthers));
3567
3568 else:
3569 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
3570
3571
3572 #
3573 # Go over a few directories in the test file set and compare names,
3574 # types and sizes rather than just the counts like we did above.
3575 #
3576 if fRc is True:
3577 oCurTest = tdTestDirRead();
3578 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3579 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: gctrlReadDirTree2');
3580 if fRc is True:
3581 for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
3582 reporter.log('Checking "%s" ...' % (oDir.sPath,));
3583 fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir) and fRc;
3584 fRc = oCurTest.closeSession() and fRc;
3585
3586 return (fRc, oTxsSession);
3587
3588
3589 def testGuestCtrlFileRemove(self, oSession, oTxsSession, oTestVm):
3590 """
3591 Tests removing guest files.
3592 """
3593
3594 #
3595 # Create a directory with a few files in it using TXS that we'll use for the initial tests.
3596 #
3597 asTestDirs = [
3598 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1'), # [0]
3599 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1'), # [1]
3600 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1', 'subsubdir-1'), # [2]
3601 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2'), # [3]
3602 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2'), # [4]
3603 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2', 'subsbudir-2'), # [5]
3604 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-3'), # [6]
3605 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-4'), # [7]
3606 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5'), # [8]
3607 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5', 'subdir-5'), # [9]
3608 ]
3609 asTestFiles = [
3610 oTestVm.pathJoin(asTestDirs[0], 'file-0'), # [0]
3611 oTestVm.pathJoin(asTestDirs[0], 'file-1'), # [1]
3612 oTestVm.pathJoin(asTestDirs[0], 'file-2'), # [2]
3613 oTestVm.pathJoin(asTestDirs[1], 'file-3'), # [3] - subdir-1
3614 oTestVm.pathJoin(asTestDirs[1], 'file-4'), # [4] - subdir-1
3615 oTestVm.pathJoin(asTestDirs[2], 'file-5'), # [5] - subsubdir-1
3616 oTestVm.pathJoin(asTestDirs[3], 'file-6'), # [6] - rmtestdir-2
3617 oTestVm.pathJoin(asTestDirs[4], 'file-7'), # [7] - subdir-2
3618 oTestVm.pathJoin(asTestDirs[5], 'file-8'), # [8] - subsubdir-2
3619 ];
3620 for sDir in asTestDirs:
3621 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
3622 return reporter.error('Failed to create test dir "%s"!' % (sDir,));
3623 for sFile in asTestFiles:
3624 if oTxsSession.syncUploadString(sFile, sFile, 0o666) is not True:
3625 return reporter.error('Failed to create test file "%s"!' % (sFile,));
3626
3627 #
3628 # Tear down the directories and files.
3629 #
3630 aoTests = [
3631 # Negative tests first:
3632 tdTestRemoveFile(asTestDirs[0], fRcExpect = False),
3633 tdTestRemoveDir(asTestDirs[0], fRcExpect = False),
3634 tdTestRemoveDir(asTestFiles[0], fRcExpect = False),
3635 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-file'), fRcExpect = False),
3636 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir'), fRcExpect = False),
3637 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-file'), fRcExpect = False),
3638 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-subdir'), fRcExpect = False),
3639 tdTestRemoveTree(asTestDirs[0], afFlags = [], fRcExpect = False), # Only removes empty dirs, this isn't empty.
3640 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fRcExpect = False), # ditto
3641 # Empty paths:
3642 tdTestRemoveFile('', fRcExpect = False),
3643 tdTestRemoveDir('', fRcExpect = False),
3644 tdTestRemoveTree('', fRcExpect = False),
3645 # Now actually remove stuff:
3646 tdTestRemoveDir(asTestDirs[7], fRcExpect = True),
3647 tdTestRemoveFile(asTestDirs[6], fRcExpect = False),
3648 tdTestRemoveDir(asTestDirs[6], fRcExpect = True),
3649 tdTestRemoveFile(asTestFiles[0], fRcExpect = True),
3650 tdTestRemoveFile(asTestFiles[0], fRcExpect = False),
3651 # 17:
3652 tdTestRemoveTree(asTestDirs[8], fRcExpect = True), # Removes empty subdirs and leaves the dir itself.
3653 tdTestRemoveDir(asTestDirs[8], fRcExpect = True),
3654 tdTestRemoveTree(asTestDirs[3], fRcExpect = False), # Have subdirs & files,
3655 tdTestRemoveTree(asTestDirs[3], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,], fRcExpect = True),
3656 tdTestRemoveDir(asTestDirs[3], fRcExpect = True),
3657 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
3658 # No error if already delete (RTDirRemoveRecursive artifact).
3659 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
3660 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,],
3661 fNotExist = True, fRcExpect = True),
3662 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fNotExist = True, fRcExpect = True),
3663 ];
3664
3665 #
3666 # Execution loop
3667 #
3668 fRc = True;
3669 for (i, oTest) in enumerate(aoTests): # int, tdTestRemoveBase
3670 reporter.log('Testing #%d, path="%s" %s ...' % (i, oTest.sPath, oTest.__class__.__name__));
3671 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
3672 fRc, _ = oTest.createSession('testGuestCtrlFileRemove: Test #%d' % (i,));
3673 if fRc is False:
3674 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3675 break;
3676 fRc = oTest.execute(self) and fRc;
3677 fRc = oTest.closeSession() and fRc;
3678
3679 if fRc is True:
3680 oCurTest = tdTestDirRead();
3681 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3682 fRc, oCurGuestSession = oCurTest.createSession('remove final');
3683 if fRc is True:
3684
3685 #
3686 # Delete all the files in the many subdir of the test set.
3687 #
3688 reporter.log('Deleting the file in "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
3689 for oFile in self.oTestFiles.oManyDir.aoChildren:
3690 reporter.log2('"%s"' % (oFile.sPath,));
3691 try:
3692 if self.oTstDrv.fpApiVer >= 5.0:
3693 oCurGuestSession.fsObjRemove(oFile.sPath);
3694 else:
3695 oCurGuestSession.fileRemove(oFile.sPath);
3696 except:
3697 fRc = reporter.errorXcpt('Removing "%s" failed' % (oFile.sPath,));
3698
3699 # Remove the directory itself to verify that we've removed all the files in it:
3700 reporter.log('Removing the directory "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
3701 try:
3702 oCurGuestSession.directoryRemove(self.oTestFiles.oManyDir.sPath);
3703 except:
3704 fRc = reporter.errorXcpt('Removing directory "%s" failed' % (self.oTestFiles.oManyDir.sPath,));
3705
3706 #
3707 # Recursively delete the entire test file tree from the root up.
3708 #
3709 # Note! On unix we cannot delete the root dir itself since it is residing
3710 # in /var/tmp where only the owner may delete it. Root is the owner.
3711 #
3712 if oTestVm.isWindows() or oTestVm.isOS2():
3713 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,];
3714 else:
3715 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,];
3716 try:
3717 oProgress = oCurGuestSession.directoryRemoveRecursive(self.oTestFiles.oRoot.sPath, afFlags);
3718 except:
3719 fRc = reporter.errorXcpt('Removing tree "%s" failed' % (self.oTestFiles.oRoot.sPath,));
3720 else:
3721 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv,
3722 "remove-tree-root: %s" % (self.oTestFiles.oRoot.sPath,));
3723 reporter.log2('waiting ...')
3724 oWrappedProgress.wait();
3725 reporter.log2('isSuccess=%s' % (oWrappedProgress.isSuccess(),));
3726 if not oWrappedProgress.isSuccess():
3727 fRc = oWrappedProgress.logResult();
3728
3729 fRc = oCurTest.closeSession() and fRc;
3730
3731 return (fRc, oTxsSession);
3732
3733
3734 def testGuestCtrlFileStat(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3735 """
3736 Tests querying file information through stat.
3737 """
3738
3739 # Basic stuff, existing stuff.
3740 aoTests = [
3741 tdTestSessionEx([
3742 tdStepStatDir('.'),
3743 tdStepStatDir('..'),
3744 tdStepStatDir(self.getGuestTempDir(oTestVm)),
3745 tdStepStatDir(self.getGuestSystemDir(oTestVm)),
3746 tdStepStatDirEx(self.oTestFiles.oRoot),
3747 tdStepStatDirEx(self.oTestFiles.oEmptyDir),
3748 tdStepStatDirEx(self.oTestFiles.oTreeDir),
3749 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3750 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3751 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3752 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3753 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3754 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
3755 tdStepStatFile(self.getGuestSystemFileForReading(oTestVm)),
3756 tdStepStatFile(self.getGuestSystemShell(oTestVm)),
3757 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3758 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3759 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3760 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3761 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3762 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
3763 ]),
3764 ];
3765
3766 # None existing stuff.
3767 sSysDir = self.getGuestSystemDir(oTestVm);
3768 sSep = oTestVm.pathSep();
3769 aoTests += [
3770 tdTestSessionEx([
3771 tdStepStatFileNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory')),
3772 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory') + sSep),
3773 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', '.')),
3774 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory')),
3775 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory') + sSep),
3776 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory', '.')),
3777 #tdStepStatPathNotFound('N:\\'), # ASSUMES nothing mounted on N:!
3778 #tdStepStatPathNotFound('\\\\NoSuchUncServerName\\NoSuchShare'),
3779 ]),
3780 ];
3781 # Invalid parameter check.
3782 aoTests += [ tdTestSessionEx([ tdStepStat('', vbox.ComError.E_INVALIDARG), ]), ];
3783
3784 #
3785 # Execute the tests.
3786 #
3787 fRc, oTxsSession = tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession,
3788 oTestVm, 'FsStat');
3789 #
3790 # Test the full test file set.
3791 #
3792 if self.oTstDrv.fpApiVer < 5.0:
3793 return (fRc, oTxsSession);
3794
3795 oTest = tdTestGuestCtrlBase();
3796 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
3797 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
3798 if fRc2 is not True:
3799 return (False, oTxsSession);
3800
3801 for sPath in self.oTestFiles.dPaths:
3802 oFsObj = self.oTestFiles.dPaths[sPath];
3803 reporter.log2('testGuestCtrlFileStat: %s sPath=%s'
3804 % ('file' if isinstance(oFsObj, testfileset.TestFile) else 'dir ', oFsObj.sPath,));
3805
3806 # Query the information:
3807 try:
3808 oFsInfo = oGuestSession.fsObjQueryInfo(oFsObj.sPath, False);
3809 except:
3810 fRc = reporter.errorXcpt('sPath=%s type=%s: fsObjQueryInfo trouble!' % (oFsObj.sPath, type(oFsObj),));
3811 continue;
3812 if oFsInfo is None:
3813 fRc = reporter.error('sPath=%s type=%s: No info object returned!' % (oFsObj.sPath, type(oFsObj),));
3814 continue;
3815
3816 # Check attributes:
3817 try:
3818 eType = oFsInfo.type;
3819 cbObject = oFsInfo.objectSize;
3820 except:
3821 fRc = reporter.errorXcpt('sPath=%s type=%s: attribute access trouble!' % (oFsObj.sPath, type(oFsObj),));
3822 continue;
3823
3824 if isinstance(oFsObj, testfileset.TestFile):
3825 if eType != vboxcon.FsObjType_File:
3826 fRc = reporter.error('sPath=%s type=file: eType=%s, expected %s!'
3827 % (oFsObj.sPath, eType, vboxcon.FsObjType_File));
3828 if cbObject != oFsObj.cbContent:
3829 fRc = reporter.error('sPath=%s type=file: cbObject=%s, expected %s!'
3830 % (oFsObj.sPath, cbObject, oFsObj.cbContent));
3831 fFileExists = True;
3832 fDirExists = False;
3833 elif isinstance(oFsObj, testfileset.TestDir):
3834 if eType != vboxcon.FsObjType_Directory:
3835 fRc = reporter.error('sPath=%s type=dir: eType=%s, expected %s!'
3836 % (oFsObj.sPath, eType, vboxcon.FsObjType_Directory));
3837 fFileExists = False;
3838 fDirExists = True;
3839 else:
3840 fRc = reporter.error('sPath=%s type=%s: Unexpected oFsObj type!' % (oFsObj.sPath, type(oFsObj),));
3841 continue;
3842
3843 # Check the directoryExists and fileExists results too.
3844 try:
3845 fExistsResult = oGuestSession.fileExists(oFsObj.sPath, False);
3846 except:
3847 fRc = reporter.errorXcpt('sPath=%s type=%s: fileExists trouble!' % (oFsObj.sPath, type(oFsObj),));
3848 else:
3849 if fExistsResult != fFileExists:
3850 fRc = reporter.error('sPath=%s type=%s: fileExists returned %s, expected %s!'
3851 % (oFsObj.sPath, type(oFsObj), fExistsResult, fFileExists));
3852 try:
3853 fExistsResult = oGuestSession.directoryExists(oFsObj.sPath, False);
3854 except:
3855 fRc = reporter.errorXcpt('sPath=%s type=%s: directoryExists trouble!' % (oFsObj.sPath, type(oFsObj),));
3856 else:
3857 if fExistsResult != fDirExists:
3858 fRc = reporter.error('sPath=%s type=%s: directoryExists returned %s, expected %s!'
3859 % (oFsObj.sPath, type(oFsObj), fExistsResult, fDirExists));
3860
3861 fRc = oTest.closeSession() and fRc;
3862 return (fRc, oTxsSession);
3863
3864 def testGuestCtrlFileOpen(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3865 """
3866 Tests opening guest files.
3867 """
3868 if self.oTstDrv.fpApiVer < 5.0:
3869 reporter.log('Skipping because of pre 5.0 API');
3870 return None;
3871
3872 #
3873 # Paths.
3874 #
3875 sTempDir = self.getGuestTempDir(oTestVm);
3876 sFileForReading = self.getGuestSystemFileForReading(oTestVm);
3877 asFiles = [
3878 oTestVm.pathJoin(sTempDir, 'file-open-0'),
3879 oTestVm.pathJoin(sTempDir, 'file-open-1'),
3880 oTestVm.pathJoin(sTempDir, 'file-open-2'),
3881 oTestVm.pathJoin(sTempDir, 'file-open-3'),
3882 oTestVm.pathJoin(sTempDir, 'file-open-4'),
3883 ];
3884 asNonEmptyFiles = [
3885 oTestVm.pathJoin(sTempDir, 'file-open-10'),
3886 oTestVm.pathJoin(sTempDir, 'file-open-11'),
3887 oTestVm.pathJoin(sTempDir, 'file-open-12'),
3888 oTestVm.pathJoin(sTempDir, 'file-open-13'),
3889 ];
3890 sContent = 'abcdefghijklmnopqrstuvwxyz0123456789';
3891 for sFile in asNonEmptyFiles:
3892 if oTxsSession.syncUploadString(sContent, sFile, 0o666) is not True:
3893 return reporter.error('Failed to create "%s" via TXS' % (sFile,));
3894
3895 #
3896 # The tests.
3897 #
3898 atTests = [
3899 # Invalid stuff.
3900 [ tdTestFileOpen(sFile = ''), tdTestResultFailure() ],
3901 # Wrong open mode.
3902 [ tdTestFileOpen(sFile = sFileForReading, eAccessMode = -1), tdTestResultFailure() ],
3903 # Wrong disposition.
3904 [ tdTestFileOpen(sFile = sFileForReading, eAction = -1), tdTestResultFailure() ],
3905 # Non-existing file or path.
3906 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir')), tdTestResultFailure() ],
3907 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3908 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3909 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3910 eAccessMode = vboxcon.FileAccessMode_WriteOnly,
3911 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3912 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
3913 eAccessMode = vboxcon.FileAccessMode_ReadWrite,
3914 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
3915 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-dir', 'no-such-file')), tdTestResultFailure() ],
3916 ];
3917 if self.oTstDrv.fpApiVer > 5.2: # Fixed since 6.0.
3918 atTests.extend([
3919 # Wrong type:
3920 [ tdTestFileOpen(sFile = self.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3921 [ tdTestFileOpen(sFile = self.getGuestSystemDir(oTestVm)), tdTestResultFailure() ],
3922 ]);
3923 atTests.extend([
3924 # O_EXCL and such:
3925 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew,
3926 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
3927 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew), tdTestResultFailure() ],
3928 # Open a file.
3929 [ tdTestFileOpen(sFile = sFileForReading), tdTestResultSuccess() ],
3930 [ tdTestFileOpen(sFile = sFileForReading,
3931 eAction = vboxcon.FileOpenAction_OpenOrCreate), tdTestResultSuccess() ],
3932 # Create a new file.
3933 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
3934 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3935 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
3936 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
3937 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExisting,
3938 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3939 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3940 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3941 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenOrCreate,
3942 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3943 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExistingTruncated,
3944 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3945 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3946 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3947 # Open or create a new file.
3948 [ tdTestFileOpenCheckSize(sFile = asFiles[1], eAction = vboxcon.FileOpenAction_OpenOrCreate,
3949 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3950 # Create or replace a new file.
3951 [ tdTestFileOpenCheckSize(sFile = asFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3952 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3953 # Create and append to file (weird stuff).
3954 [ tdTestFileOpenCheckSize(sFile = asFiles[3], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3955 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3956 [ tdTestFileOpenCheckSize(sFile = asFiles[4], eAction = vboxcon.FileOpenAction_AppendOrCreate,
3957 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3958 # Open the non-empty files in non-destructive modes.
3959 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent)), tdTestResultSuccess() ],
3960 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3961 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3962 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3963 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3964
3965 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
3966 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3967 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3968 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3969 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3970 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3971 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3972 eAction = vboxcon.FileOpenAction_OpenOrCreate,
3973 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3974
3975 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
3976 eAction = vboxcon.FileOpenAction_AppendOrCreate,
3977 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
3978 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
3979 eAction = vboxcon.FileOpenAction_AppendOrCreate,
3980 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3981 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
3982 eAction = vboxcon.FileOpenAction_AppendOrCreate,
3983 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3984
3985 # Now the destructive stuff:
3986 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
3987 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultSuccess() ],
3988 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
3989 eAction = vboxcon.FileOpenAction_CreateOrReplace), tdTestResultSuccess() ],
3990 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
3991 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
3992 ]);
3993
3994 #
3995 # Do the testing.
3996 #
3997 fRc = True;
3998 for (i, tTest) in enumerate(atTests):
3999 oCurTest = tTest[0] # type: tdTestFileOpen
4000 oCurRes = tTest[1] # type: tdTestResult
4001
4002 reporter.log('Testing #%d: %s - sFile="%s", eAccessMode=%d, eAction=%d, (%s, %s, %s) ...'
4003 % (i, oCurTest.__class__.__name__, oCurTest.sFile, oCurTest.eAccessMode, oCurTest.eAction,
4004 oCurTest.eSharing, oCurTest.fCreationMode, oCurTest.afOpenFlags,));
4005
4006 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4007 fRc, _ = oCurTest.createSession('testGuestCtrlFileOpen: Test #%d' % (i,));
4008 if fRc is not True:
4009 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4010 break;
4011
4012 fRc2 = oCurTest.doSteps(oCurRes.fRc, self);
4013 if fRc2 != oCurRes.fRc:
4014 fRc = reporter.error('Test #%d result mismatch: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
4015
4016 fRc = oCurTest.closeSession() and fRc;
4017
4018 return (fRc, oTxsSession);
4019
4020
4021 def testGuestCtrlFileRead(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-branches,too-many-statements
4022 """
4023 Tests reading from guest files.
4024 """
4025 if self.oTstDrv.fpApiVer < 5.0:
4026 reporter.log('Skipping because of pre 5.0 API');
4027 return None;
4028
4029 #
4030 # Do everything in one session.
4031 #
4032 oTest = tdTestGuestCtrlBase();
4033 oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4034 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4035 if fRc2 is not True:
4036 return (False, oTxsSession);
4037
4038 #
4039 # Create a really big zero filled, up to 1 GiB, adding it to the list of
4040 # files from the set.
4041 #
4042 # Note! This code sucks a bit because we don't have a working setSize nor
4043 # any way to figure out how much free space there is in the guest.
4044 #
4045 aoExtraFiles = [];
4046 sBigName = self.oTestFiles.generateFilenameEx();
4047 sBigPath = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sBigName);
4048 fRc = True;
4049 try:
4050 oFile = oGuestSession.fileOpenEx(sBigPath, vboxcon.FileAccessMode_ReadWrite, vboxcon.FileOpenAction_CreateOrReplace,
4051 vboxcon.FileSharingMode_All, 0, []);
4052 except:
4053 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4054 else:
4055 # Does setSize work now?
4056 fUseFallback = True;
4057 try:
4058 oFile.setSize(0);
4059 oFile.setSize(64);
4060 fUseFallback = False;
4061 except Exception as oXcpt:
4062 reporter.logXcpt();
4063
4064 # Grow the file till we hit trouble, typical VERR_DISK_FULL, then
4065 # reduce the file size if we have a working setSize.
4066 cbBigFile = 0;
4067 while cbBigFile < (1024 + 32)*1024*1024:
4068 if not fUseFallback:
4069 cbBigFile += 16*1024*1024;
4070 try:
4071 oFile.setSize(cbBigFile);
4072 except Exception as oXcpt:
4073 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4074 try:
4075 cbBigFile -= 16*1024*1024;
4076 oFile.setSize(cbBigFile);
4077 except:
4078 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4079 break;
4080 else:
4081 cbBigFile += 32*1024*1024;
4082 try:
4083 oFile.seek(cbBigFile, vboxcon.FileSeekOrigin_Begin);
4084 oFile.write(bytearray(1), 60*1000);
4085 except:
4086 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4087 break;
4088 try:
4089 cbBigFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4090 except:
4091 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4092 try:
4093 oFile.close();
4094 except:
4095 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4096 if fRc is True:
4097 reporter.log('Big file: %s bytes: %s' % (cbBigFile, sBigPath,));
4098 aoExtraFiles.append(testfileset.TestFileZeroFilled(None, sBigPath, cbBigFile));
4099 else:
4100 try:
4101 oGuestSession.fsObjRemove(sBigPath);
4102 except:
4103 reporter.errorXcpt('fsObjRemove(sBigName=%s)' % (sBigPath,));
4104
4105 #
4106 # Open and read all the files in the test file set.
4107 #
4108 for oTestFile in aoExtraFiles + self.oTestFiles.aoFiles: # type: testfileset.TestFile
4109 reporter.log2('Test file: %s bytes, "%s" ...' % (oTestFile.cbContent, oTestFile.sPath,));
4110
4111 #
4112 # Open it:
4113 #
4114 try:
4115 oFile = oGuestSession.fileOpenEx(oTestFile.sPath, vboxcon.FileAccessMode_ReadOnly,
4116 vboxcon.FileOpenAction_OpenExisting, vboxcon.FileSharingMode_All, 0, []);
4117 except:
4118 fRc = reporter.errorXcpt('sPath=%s' % (oTestFile.sPath, ));
4119 continue;
4120
4121 #
4122 # Read the file in different sized chunks:
4123 #
4124 if oTestFile.cbContent < 128:
4125 acbChunks = xrange(1,128);
4126 elif oTestFile.cbContent < 1024:
4127 acbChunks = (2048, 127, 63, 32, 29, 17, 16, 15, 9);
4128 elif oTestFile.cbContent < 8*1024*1024:
4129 acbChunks = (128*1024, 32*1024, 8191, 255);
4130 else:
4131 acbChunks = (768*1024, 128*1024);
4132
4133 for cbChunk in acbChunks:
4134 # Read the whole file straight thru:
4135 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... cbChunk=%s' % (cbChunk,));
4136 offFile = 0;
4137 cReads = 0;
4138 while offFile <= oTestFile.cbContent:
4139 try:
4140 abRead = oFile.read(cbChunk, 30*1000);
4141 except:
4142 fRc = reporter.errorXcpt('%s: offFile=%s cbChunk=%s cbContent=%s'
4143 % (oTestFile.sPath, offFile, cbChunk, oTestFile.cbContent));
4144 break;
4145 cbRead = len(abRead);
4146 if cbRead == 0 and offFile == oTestFile.cbContent:
4147 break;
4148 if cbRead <= 0:
4149 fRc = reporter.error('%s @%s: cbRead=%s, cbContent=%s'
4150 % (oTestFile.sPath, offFile, cbRead, oTestFile.cbContent));
4151 break;
4152 if not oTestFile.equalMemory(abRead, offFile):
4153 fRc = reporter.error('%s: read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead));
4154 break;
4155 offFile += cbRead;
4156 cReads += 1;
4157 if cReads > 8192:
4158 break;
4159
4160 # Seek to start of file.
4161 try:
4162 offFile = oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4163 except:
4164 fRc = reporter.errorXcpt('%s: error seeking to start of file' % (oTestFile.sPath,));
4165 break;
4166 if offFile != 0:
4167 fRc = reporter.error('%s: seek to start of file returned %u, expected 0' % (oTestFile.sPath, offFile));
4168 break;
4169
4170 #
4171 # Random reads.
4172 #
4173 for _ in xrange(8):
4174 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4175 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4176 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s' % (offFile, cbToRead,));
4177
4178 try:
4179 offActual = oFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
4180 except:
4181 fRc = reporter.errorXcpt('%s: error seeking to %s' % (oTestFile.sPath, offFile));
4182 break;
4183 if offActual != offFile:
4184 fRc = reporter.error('%s: seek(%s,Begin) -> %s, expected %s'
4185 % (oTestFile.sPath, offFile, offActual, offFile));
4186 break;
4187
4188 try:
4189 abRead = oFile.read(cbToRead, 30*1000);
4190 except:
4191 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4192 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4193 cbRead = 0;
4194 else:
4195 cbRead = len(abRead);
4196 if not oTestFile.equalMemory(abRead, offFile):
4197 fRc = reporter.error('%s: random read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4198
4199 try:
4200 offActual = oFile.offset;
4201 except:
4202 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4203 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4204 else:
4205 if offActual != offFile + cbRead:
4206 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4207 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4208 try:
4209 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4210 except:
4211 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4212 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4213 else:
4214 if offActual != offFile + cbRead:
4215 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4216 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4217
4218 #
4219 # Random reads using readAt.
4220 #
4221 for _ in xrange(12):
4222 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4223 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4224 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s (readAt)' % (offFile, cbToRead,));
4225
4226 try:
4227 abRead = oFile.readAt(offFile, cbToRead, 30*1000);
4228 except:
4229 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4230 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4231 cbRead = 0;
4232 else:
4233 cbRead = len(abRead);
4234 if not oTestFile.equalMemory(abRead, offFile):
4235 fRc = reporter.error('%s: random readAt mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4236
4237 try:
4238 offActual = oFile.offset;
4239 except:
4240 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4241 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4242 else:
4243 if offActual != offFile + cbRead:
4244 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4245 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4246
4247 try:
4248 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4249 except:
4250 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4251 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4252 else:
4253 if offActual != offFile + cbRead:
4254 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4255 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4256
4257 #
4258 # A few negative things.
4259 #
4260
4261 # Zero byte reads -> E_INVALIDARG.
4262 try:
4263 abRead = oFile.read(0, 30*1000);
4264 except Exception as oXcpt:
4265 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4266 fRc = reporter.errorXcpt('read(0,30s) did not raise E_INVALIDARG as expected!');
4267 else:
4268 fRc = reporter.error('read(0,30s) did not fail!');
4269
4270 try:
4271 abRead = oFile.readAt(0, 0, 30*1000);
4272 except Exception as oXcpt:
4273 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4274 fRc = reporter.errorXcpt('readAt(0,0,30s) did not raise E_INVALIDARG as expected!');
4275 else:
4276 fRc = reporter.error('readAt(0,0,30s) did not fail!');
4277
4278 # See what happens when we read 1GiB. We should get a max of 1MiB back.
4279 ## @todo Document this behaviour in VirtualBox.xidl.
4280 try:
4281 oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4282 except:
4283 fRc = reporter.error('seek(0)');
4284 try:
4285 abRead = oFile.read(1024*1024*1024, 30*1000);
4286 except:
4287 fRc = reporter.errorXcpt('read(1GiB,30s)');
4288 else:
4289 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4290 fRc = reporter.error('Expected read(1GiB,30s) to return %s bytes, got %s bytes instead'
4291 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4292
4293 try:
4294 abRead = oFile.readAt(0, 1024*1024*1024, 30*1000);
4295 except:
4296 fRc = reporter.errorXcpt('readAt(0,1GiB,30s)');
4297 else:
4298 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4299 reporter.error('Expected readAt(0, 1GiB,30s) to return %s bytes, got %s bytes instead'
4300 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4301
4302 #
4303 # Check stat info on the file as well as querySize.
4304 #
4305 if self.oTstDrv.fpApiVer > 5.2:
4306 try:
4307 oFsObjInfo = oFile.queryInfo();
4308 except:
4309 fRc = reporter.errorXcpt('%s: queryInfo()' % (oTestFile.sPath,));
4310 else:
4311 if oFsObjInfo is None:
4312 fRc = reporter.error('IGuestFile::queryInfo returned None');
4313 else:
4314 try:
4315 cbFile = oFsObjInfo.objectSize;
4316 except:
4317 fRc = reporter.errorXcpt();
4318 else:
4319 if cbFile != oTestFile.cbContent:
4320 fRc = reporter.error('%s: queryInfo returned incorrect file size: %s, expected %s'
4321 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4322
4323 try:
4324 cbFile = oFile.querySize();
4325 except:
4326 fRc = reporter.errorXcpt('%s: querySize()' % (oTestFile.sPath,));
4327 else:
4328 if cbFile != oTestFile.cbContent:
4329 fRc = reporter.error('%s: querySize returned incorrect file size: %s, expected %s'
4330 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4331
4332 #
4333 # Use seek to test the file size and do a few other end-relative seeks.
4334 #
4335 try:
4336 cbFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4337 except:
4338 fRc = reporter.errorXcpt('%s: seek(0,End)' % (oTestFile.sPath,));
4339 else:
4340 if cbFile != oTestFile.cbContent:
4341 fRc = reporter.error('%s: seek(0,End) returned incorrect file size: %s, expected %s'
4342 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4343 if oTestFile.cbContent > 0:
4344 for _ in xrange(5):
4345 offSeek = self.oTestFiles.oRandom.randrange(oTestFile.cbContent + 1);
4346 try:
4347 offFile = oFile.seek(-offSeek, vboxcon.FileSeekOrigin_End);
4348 except:
4349 fRc = reporter.errorXcpt('%s: seek(%s,End)' % (oTestFile.sPath, -offSeek,));
4350 else:
4351 if offFile != oTestFile.cbContent - offSeek:
4352 fRc = reporter.error('%s: seek(%s,End) returned incorrect offset: %s, expected %s (cbContent=%s)'
4353 % (oTestFile.sPath, -offSeek, offSeek, oTestFile.cbContent - offSeek,
4354 oTestFile.cbContent,));
4355
4356 #
4357 # Close it and we're done with this file.
4358 #
4359 try:
4360 oFile.close();
4361 except:
4362 fRc = reporter.errorXcpt('%s: error closing the file' % (oTestFile.sPath,));
4363
4364 #
4365 # Clean up.
4366 #
4367 for oTestFile in aoExtraFiles:
4368 try:
4369 oGuestSession.fsObjRemove(sBigPath);
4370 except:
4371 fRc = reporter.errorXcpt('fsObjRemove(%s)' % (sBigPath,));
4372
4373 fRc = oTest.closeSession() and fRc;
4374
4375 return (fRc, oTxsSession);
4376
4377
4378 def testGuestCtrlFileWrite(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4379 """
4380 Tests writing to guest files.
4381 """
4382 if self.oTstDrv.fpApiVer < 5.0:
4383 reporter.log('Skipping because of pre 5.0 API');
4384 return None;
4385
4386 #
4387 # The test file and its content.
4388 #
4389 sFile = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'gctrl-write-1');
4390 abContent = bytearray(0);
4391
4392 #
4393 # The tests.
4394 #
4395 def randBytes(cbHowMany):
4396 """ Returns an bytearray of random bytes. """
4397 return bytearray(self.oTestFiles.oRandom.getrandbits(8) for _ in xrange(cbHowMany));
4398
4399 aoTests = [
4400 # Write at end:
4401 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_CreateNew, abContent = abContent,
4402 atChunks = [(None, randBytes(1)), (None, randBytes(77)), (None, randBytes(98)),]),
4403 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1+77+98), # 176
4404 # Appending:
4405 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
4406 atChunks = [(None, randBytes(255)), (None, randBytes(33)),]),
4407 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 176 + 255+33), # 464
4408 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
4409 atChunks = [(10, randBytes(44)),]),
4410 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 464 + 44), # 508
4411 # Write within existing:
4412 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_OpenExisting, abContent = abContent,
4413 atChunks = [(0, randBytes(1)), (50, randBytes(77)), (255, randBytes(199)),]),
4414 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 508),
4415 # Writing around and over the end:
4416 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent,
4417 atChunks = [(500, randBytes(9)), (508, randBytes(15)), (512, randBytes(12)),]),
4418 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 512+12),
4419
4420 # writeAt appending:
4421 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4422 atChunks = [(0, randBytes(23)), (6, randBytes(1018)),]),
4423 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 6+1018), # 1024
4424 # writeAt within existing:
4425 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4426 atChunks = [(1000, randBytes(23)), (1, randBytes(990)),]),
4427 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1024),
4428 # writeAt around and over the end:
4429 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
4430 atChunks = [(1024, randBytes(63)), (1080, randBytes(968)),]),
4431 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1080+968), # 2048
4432
4433 # writeAt beyond the end (gap is filled with zeros):
4434 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True, atChunks = [(3070, randBytes(2)),]),
4435 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 3072),
4436 # write beyond the end (gap is filled with zeros):
4437 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, atChunks = [(4090, randBytes(6)),]),
4438 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 4096),
4439 ];
4440
4441 for (i, oCurTest) in enumerate(aoTests):
4442 reporter.log('Testing #%d: %s ...' % (i, oCurTest.toString(),));
4443
4444 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4445 fRc, _ = oCurTest.createSession('testGuestCtrlFileWrite: Test #%d' % (i,));
4446 if fRc is not True:
4447 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4448 break;
4449
4450 fRc2 = oCurTest.doSteps(True, self);
4451 if fRc2 is not True:
4452 fRc = reporter.error('Test #%d failed!' % (i,));
4453
4454 fRc = oCurTest.closeSession() and fRc;
4455
4456 #
4457 # Cleanup
4458 #
4459 if oTxsSession.syncRmFile(sFile) is not True:
4460 fRc = reporter.error('Failed to remove write-test file: %s' % (sFile, ));
4461
4462 return (fRc, oTxsSession);
4463
4464 @staticmethod
4465 def __generateFile(sName, cbFile):
4466 """ Helper for generating a file with a given size. """
4467 oFile = open(sName, 'wb');
4468 while cbFile > 0:
4469 cb = cbFile if cbFile < 256*1024 else 256*1024;
4470 oFile.write(bytearray(random.getrandbits(8) for _ in xrange(cb)));
4471 cbFile -= cb;
4472 oFile.close();
4473
4474 def testGuestCtrlCopyTo(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4475 """
4476 Tests copying files from host to the guest.
4477 """
4478
4479 #
4480 # Paths and test files.
4481 #
4482 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, 'copyto');
4483 sScratchTestFilesHst = os.path.join(sScratchHst, self.oTestFiles.sSubDir);
4484 sScratchEmptyDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oEmptyDir.sName);
4485 sScratchNonEmptyDirHst = self.oTestFiles.chooseRandomDirFromTree().buildPath(sScratchHst, os.path.sep);
4486 sScratchTreeDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oTreeDir.sName);
4487
4488 sScratchGst = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'copyto');
4489 sScratchDstDir1Gst = oTestVm.pathJoin(sScratchGst, 'dstdir1');
4490 sScratchDstDir2Gst = oTestVm.pathJoin(sScratchGst, 'dstdir2');
4491 sScratchDstDir3Gst = oTestVm.pathJoin(sScratchGst, 'dstdir3');
4492 sScratchDstDir4Gst = oTestVm.pathJoin(sScratchGst, 'dstdir4');
4493 #sScratchGstNotExist = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'no-such-file-or-directory');
4494 sScratchHstNotExist = os.path.join(self.oTstDrv.sScratchPath, 'no-such-file-or-directory');
4495 sScratchGstPathNotFound = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'no-such-directory', 'or-file');
4496 #sScratchHstPathNotFound = os.path.join(self.oTstDrv.sScratchPath, 'no-such-directory', 'or-file');
4497
4498 if oTestVm.isWindows() or oTestVm.isOS2():
4499 sScratchGstInvalid = "?*|<invalid-name>";
4500 else:
4501 sScratchGstInvalid = None;
4502 if utils.getHostOs() in ('win', 'os2'):
4503 sScratchHstInvalid = "?*|<invalid-name>";
4504 else:
4505 sScratchHstInvalid = None;
4506
4507 for sDir in (sScratchGst, sScratchDstDir1Gst, sScratchDstDir2Gst, sScratchDstDir3Gst, sScratchDstDir4Gst):
4508 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
4509 return reporter.error('TXS failed to create directory "%s"!' % (sDir,));
4510
4511 # Put the test file set under sScratchHst.
4512 if os.path.exists(sScratchHst):
4513 if base.wipeDirectory(sScratchHst) != 0:
4514 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
4515 else:
4516 try:
4517 os.mkdir(sScratchHst);
4518 except:
4519 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
4520 if self.oTestFiles.writeToDisk(sScratchHst) is not True:
4521 return reporter.error('Filed to write test files to "%s" on the host!' % (sScratchHst,));
4522
4523 # Generate a test file in 32MB to 64 MB range.
4524 sBigFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-random.data');
4525 cbBigFileHst = random.randrange(32*1024*1024, 64*1024*1024);
4526 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
4527 cbLeft = cbBigFileHst;
4528 try:
4529 self.__generateFile(sBigFileHst, cbBigFileHst);
4530 except:
4531 return reporter.errorXcpt('sBigFileHst=%s cbBigFileHst=%s cbLeft=%s' % (sBigFileHst, cbBigFileHst, cbLeft,));
4532 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
4533
4534 # Generate an empty file on the host that we can use to save space in the guest.
4535 sEmptyFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-empty.data');
4536 try:
4537 oFile = open(sEmptyFileHst, "wb");
4538 oFile.close();
4539 except:
4540 return reporter.errorXcpt('sEmptyFileHst=%s' % (sEmptyFileHst,));
4541
4542 #
4543 # Tests.
4544 #
4545 atTests = [
4546 # Nothing given:
4547 [ tdTestCopyToFile(), tdTestResultFailure() ],
4548 [ tdTestCopyToDir(), tdTestResultFailure() ],
4549 # Only source given:
4550 [ tdTestCopyToFile(sSrc = sBigFileHst), tdTestResultFailure() ],
4551 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst), tdTestResultFailure() ],
4552 # Only destination given:
4553 [ tdTestCopyToFile(sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')), tdTestResultFailure() ],
4554 [ tdTestCopyToDir( sDst = sScratchGst), tdTestResultFailure() ],
4555 # Both given, but invalid flags.
4556 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst, afFlags = [ 0x40000000] ), tdTestResultFailure() ],
4557 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGst, afFlags = [ 0x40000000] ),
4558 tdTestResultFailure() ],
4559 ];
4560 atTests.extend([
4561 # Non-existing source, but no destination:
4562 [ tdTestCopyToFile(sSrc = sScratchHstNotExist), tdTestResultFailure() ],
4563 [ tdTestCopyToDir( sSrc = sScratchHstNotExist), tdTestResultFailure() ],
4564 # Valid sources, but destination path not found:
4565 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
4566 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
4567 # Valid destination, but source file/dir not found:
4568 [ tdTestCopyToFile(sSrc = sScratchHstNotExist, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
4569 tdTestResultFailure() ],
4570 [ tdTestCopyToDir( sSrc = sScratchHstNotExist, sDst = sScratchGst), tdTestResultFailure() ],
4571 # Wrong type:
4572 [ tdTestCopyToFile(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
4573 tdTestResultFailure() ],
4574 [ tdTestCopyToDir( sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultFailure() ],
4575 ]);
4576 # Invalid characters in destination or source path:
4577 if sScratchGstInvalid is not None:
4578 atTests.extend([
4579 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
4580 tdTestResultFailure() ],
4581 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
4582 tdTestResultFailure() ],
4583 ]);
4584 if sScratchHstInvalid is not None:
4585 atTests.extend([
4586 [ tdTestCopyToFile(sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
4587 tdTestResultFailure() ],
4588 [ tdTestCopyToDir( sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
4589 tdTestResultFailure() ],
4590 ]);
4591
4592 #
4593 # Single file handling.
4594 #
4595 atTests.extend([
4596 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')),
4597 tdTestResultSuccess() ],
4598 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
4599 tdTestResultSuccess() ],
4600 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
4601 tdTestResultSuccess() ],
4602 ]);
4603 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
4604 atTests.extend([
4605 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultSuccess() ],
4606 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultSuccess() ], # Overwrite
4607 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, os.path.split(sBigFileHst)[1])),
4608 tdTestResultSuccess() ], # Overwrite
4609 ]);
4610
4611 if oTestVm.isWindows():
4612 # Copy to a Windows alternative data stream (ADS).
4613 atTests.extend([
4614 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
4615 tdTestResultSuccess() ],
4616 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
4617 tdTestResultSuccess() ],
4618 ]);
4619
4620 #
4621 # Directory handling.
4622 #
4623 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
4624 atTests.extend([
4625 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
4626 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4627 # Try again.
4628 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
4629 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4630 # Should fail, as destination directory already exists.
4631 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst), tdTestResultFailure() ],
4632 # Try again with trailing slash, should yield the same result:
4633 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
4634 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4635 # Try again.
4636 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
4637 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4638 # Should fail, as destination directory already exists.
4639 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
4640 tdTestResultFailure() ],
4641 # Copy with a different destination name just for the heck of it:
4642 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchDstDir1Gst, 'empty2')),
4643 tdTestResultSuccess() ],
4644 ]);
4645 atTests.extend([
4646 # Now the same using a directory with files in it:
4647 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
4648 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4649 # Again.
4650 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
4651 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4652 # Should fail, as directory is existing already.
4653 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst), tdTestResultFailure() ],
4654 ]);
4655 atTests.extend([
4656 # Copy the entire test tree:
4657 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst,
4658 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting]), tdTestResultSuccess() ],
4659 ]);
4660
4661 fRc = True;
4662 for (i, tTest) in enumerate(atTests):
4663 oCurTest = tTest[0]; # tdTestCopyTo
4664 oCurRes = tTest[1]; # tdTestResult
4665 reporter.log('Testing #%d, sSrc=%s, sDst=%s, afFlags=%s ...' % (i, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags));
4666
4667 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4668 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyTo: Test #%d' % (i,));
4669 if fRc is not True:
4670 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4671 break;
4672
4673 fRc2 = False;
4674 if isinstance(oCurTest, tdTestCopyToFile):
4675 fRc2 = self.gctrlCopyFileTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
4676 else:
4677 fRc2 = self.gctrlCopyDirTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
4678 if fRc2 is not oCurRes.fRc:
4679 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4680
4681 fRc = oCurTest.closeSession() and fRc;
4682
4683 return (fRc, oTxsSession);
4684
4685 def testGuestCtrlCopyFrom(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4686 """
4687 Tests copying files from guest to the host.
4688 """
4689
4690 #
4691 # Paths.
4692 #
4693 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, "testGctrlCopyFrom");
4694 sScratchDstDir1Hst = os.path.join(sScratchHst, "dstdir1");
4695 sScratchDstDir2Hst = os.path.join(sScratchHst, "dstdir2");
4696 sScratchDstDir3Hst = os.path.join(sScratchHst, "dstdir3");
4697 oExistingFileGst = self.oTestFiles.chooseRandomFile();
4698 oNonEmptyDirGst = self.oTestFiles.chooseRandomDirFromTree(fNonEmpty = True);
4699 oEmptyDirGst = self.oTestFiles.oEmptyDir;
4700
4701 if oTestVm.isWindows() or oTestVm.isOS2():
4702 sScratchGstInvalid = "?*|<invalid-name>";
4703 else:
4704 sScratchGstInvalid = None;
4705 if utils.getHostOs() in ('win', 'os2'):
4706 sScratchHstInvalid = "?*|<invalid-name>";
4707 else:
4708 sScratchHstInvalid = None;
4709
4710 if os.path.exists(sScratchHst):
4711 if base.wipeDirectory(sScratchHst) != 0:
4712 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
4713 else:
4714 try:
4715 os.mkdir(sScratchHst);
4716 except:
4717 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
4718
4719 for sSubDir in (sScratchDstDir1Hst, sScratchDstDir2Hst, sScratchDstDir3Hst):
4720 try:
4721 os.mkdir(sSubDir);
4722 except:
4723 return reporter.errorXcpt('os.mkdir(%s)' % (sSubDir, ));
4724
4725 #
4726 # Bad parameter tests.
4727 #
4728 atTests = [
4729 # Missing both source and destination:
4730 [ tdTestCopyFromFile(), tdTestResultFailure() ],
4731 [ tdTestCopyFromDir(), tdTestResultFailure() ],
4732 # Missing source.
4733 [ tdTestCopyFromFile(sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4734 [ tdTestCopyFromDir( sDst = sScratchHst), tdTestResultFailure() ],
4735 # Missing destination.
4736 [ tdTestCopyFromFile(oSrc = oExistingFileGst), tdTestResultFailure() ],
4737 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath), tdTestResultFailure() ],
4738 # Invalid flags:
4739 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somefile'), afFlags = [0x40000000]),
4740 tdTestResultFailure() ],
4741 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'somedir'), afFlags = [ 0x40000000] ),
4742 tdTestResultFailure() ],
4743 # Non-existing sources:
4744 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
4745 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4746 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
4747 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4748 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-file'),
4749 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4750 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-subdir'),
4751 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4752 # Non-existing destinations:
4753 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
4754 sDst = os.path.join(sScratchHst, 'no-such-directory', 'somefile') ), tdTestResultFailure() ],
4755 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'no-such-directory', 'somedir') ),
4756 tdTestResultFailure() ],
4757 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
4758 sDst = os.path.join(sScratchHst, 'no-such-directory-slash' + os.path.sep)),
4759 tdTestResultFailure() ],
4760 # Wrong source type:
4761 [ tdTestCopyFromFile(oSrc = oNonEmptyDirGst, sDst = os.path.join(sScratchHst, 'somefile') ), tdTestResultFailure() ],
4762 [ tdTestCopyFromDir(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somedir') ), tdTestResultFailure() ],
4763 ];
4764 # Bogus names:
4765 if sScratchHstInvalid:
4766 atTests.extend([
4767 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
4768 tdTestResultFailure() ],
4769 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
4770 tdTestResultFailure() ],
4771 ]);
4772 if sScratchGstInvalid:
4773 atTests.extend([
4774 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
4775 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
4776 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
4777 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
4778 ]);
4779
4780 #
4781 # Single file copying.
4782 #
4783 atTests.extend([
4784 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')),
4785 tdTestResultSuccess() ],
4786 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), # Overwrite it
4787 tdTestResultSuccess() ],
4788 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile2')),
4789 tdTestResultSuccess() ],
4790 ]);
4791 if self.oTstDrv.fpApiVer > 5.2:
4792 # Copy into a directory.
4793 atTests.extend([
4794 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst), tdTestResultSuccess() ],
4795 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
4796 ]);
4797
4798 #
4799 # Directory tree copying:
4800 #
4801 atTests.extend([
4802 # Copy the empty guest directory (should end up as sScratchHst/empty):
4803 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst), tdTestResultSuccess() ],
4804 # Repeat -- this time it should fail, as the destination directory already exists (and
4805 # DirectoryCopyFlag_CopyIntoExisting is not specified):
4806 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst), tdTestResultFailure() ],
4807 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work.
4808 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst,
4809 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4810 # Try again with trailing slash, should yield the same result:
4811 [ tdTestRemoveHostDir(os.path.join(sScratchDstDir1Hst, 'empty')), tdTestResult() ],
4812 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep),
4813 tdTestResultSuccess() ],
4814 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep),
4815 tdTestResultFailure() ],
4816 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir1Hst + os.path.sep,
4817 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4818 # Copy with a different destination name just for the heck of it:
4819 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'empty2'), fIntoDst = True),
4820 tdTestResultFailure() ],
4821 # Now the same using a directory with files in it:
4822 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst), tdTestResultSuccess() ],
4823 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst), tdTestResultFailure() ],
4824 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir2Hst,
4825 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
4826 # Copy the entire test tree:
4827 [ tdTestCopyFromDir(sSrc = self.oTestFiles.oTreeDir.sPath, sDst = sScratchDstDir3Hst), tdTestResultSuccess() ],
4828 ]);
4829
4830 #
4831 # Execute the tests.
4832 #
4833 fRc = True;
4834 for (i, tTest) in enumerate(atTests):
4835 oCurTest = tTest[0]
4836 oCurRes = tTest[1] # type: tdTestResult
4837 if isinstance(oCurTest, tdTestCopyFrom):
4838 reporter.log('Testing #%d, %s: sSrc="%s", sDst="%s", afFlags="%s" ...'
4839 % (i, "directory" if isinstance(oCurTest, tdTestCopyFromDir) else "file",
4840 oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags,));
4841 else:
4842 reporter.log('Testing #%d, tdTestRemoveHostDir "%s" ...' % (i, oCurTest.sDir,));
4843 if isinstance(oCurTest, tdTestCopyFromDir) and self.oTstDrv.fpApiVer < 6.0:
4844 reporter.log('Skipping directoryCopyFromGuest test, not implemented in %s' % (self.oTstDrv.fpApiVer,));
4845 continue;
4846
4847 if isinstance(oCurTest, tdTestRemoveHostDir):
4848 fRc = oCurTest.execute(self.oTstDrv, oSession, oTxsSession, oTestVm, 'testing #%d' % (i,));
4849 else:
4850 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4851 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyFrom: Test #%d' % (i,));
4852 if fRc2 is not True:
4853 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4854 break;
4855
4856 if isinstance(oCurTest, tdTestCopyFromFile):
4857 fRc2 = self.gctrlCopyFileFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
4858 else:
4859 fRc2 = self.gctrlCopyDirFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
4860
4861 if fRc2 != oCurRes.fRc:
4862 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4863
4864 fRc = oCurTest.closeSession() and fRc;
4865
4866 return (fRc, oTxsSession);
4867
4868 def testGuestCtrlUpdateAdditions(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4869 """
4870 Tests updating the Guest Additions inside the guest.
4871
4872 """
4873
4874 ## @todo currently disabled everywhere.
4875 if self.oTstDrv.fpApiVer < 100.0:
4876 reporter.log("Skipping updating GAs everywhere for now...");
4877 return None;
4878
4879 # Skip test for updating Guest Additions if we run on a too old (Windows) guest.
4880 ##
4881 ## @todo make it work everywhere!
4882 ##
4883 if oTestVm.sKind in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
4884 reporter.log("Skipping updating GAs on old windows vm (sKind=%s)" % (oTestVm.sKind,));
4885 return (None, oTxsSession);
4886 if oTestVm.isOS2():
4887 reporter.log("Skipping updating GAs on OS/2 guest");
4888 return (None, oTxsSession);
4889
4890 sVBoxValidationKitIso = self.oTstDrv.sVBoxValidationKitIso;
4891 if not os.path.isfile(sVBoxValidationKitIso):
4892 return reporter.log('Validation Kit .ISO not found at "%s"' % (sVBoxValidationKitIso,));
4893
4894 sScratch = os.path.join(self.oTstDrv.sScratchPath, "testGctrlUpdateAdditions");
4895 try:
4896 os.makedirs(sScratch);
4897 except OSError as e:
4898 if e.errno != errno.EEXIST:
4899 return reporter.error('Failed: Unable to create scratch directory \"%s\"' % (sScratch,));
4900 reporter.log('Scratch path is: %s' % (sScratch,));
4901
4902 atTests = [];
4903 if oTestVm.isWindows():
4904 atTests.extend([
4905 # Source is missing.
4906 [ tdTestUpdateAdditions(sSrc = ''), tdTestResultFailure() ],
4907
4908 # Wrong flags.
4909 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
4910 afFlags = [ 1234 ]), tdTestResultFailure() ],
4911
4912 # Non-existing .ISO.
4913 [ tdTestUpdateAdditions(sSrc = "non-existing.iso"), tdTestResultFailure() ],
4914
4915 # Wrong .ISO.
4916 [ tdTestUpdateAdditions(sSrc = sVBoxValidationKitIso), tdTestResultFailure() ],
4917
4918 # The real thing.
4919 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso()),
4920 tdTestResultSuccess() ],
4921 # Test the (optional) installer arguments. This will extract the
4922 # installer into our guest's scratch directory.
4923 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
4924 asArgs = [ '/extract', '/D=' + sScratch ]),
4925 tdTestResultSuccess() ]
4926 # Some debg ISO. Only enable locally.
4927 #[ tdTestUpdateAdditions(
4928 # sSrc = "V:\\Downloads\\VBoxGuestAdditions-r80354.iso"),
4929 # tdTestResultSuccess() ]
4930 ]);
4931 else:
4932 reporter.log('No OS-specific tests for non-Windows yet!');
4933
4934 fRc = True;
4935 for (i, tTest) in enumerate(atTests):
4936 oCurTest = tTest[0] # type: tdTestUpdateAdditions
4937 oCurRes = tTest[1] # type: tdTestResult
4938 reporter.log('Testing #%d, sSrc="%s", afFlags="%s" ...' % (i, oCurTest.sSrc, oCurTest.afFlags,));
4939
4940 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4941 fRc, _ = oCurTest.createSession('Test #%d' % (i,));
4942 if fRc is not True:
4943 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4944 break;
4945
4946 try:
4947 oCurProgress = oCurTest.oGuest.updateGuestAdditions(oCurTest.sSrc, oCurTest.asArgs, oCurTest.afFlags);
4948 except:
4949 reporter.maybeErrXcpt(oCurRes.fRc, 'Updating Guest Additions exception for sSrc="%s", afFlags="%s":'
4950 % (oCurTest.sSrc, oCurTest.afFlags,));
4951 fRc = False;
4952 else:
4953 if oCurProgress is not None:
4954 oWrapperProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr,
4955 self.oTstDrv, "gctrlUpGA");
4956 oWrapperProgress.wait();
4957 if not oWrapperProgress.isSuccess():
4958 oWrapperProgress.logResult(fIgnoreErrors = not oCurRes.fRc);
4959 fRc = False;
4960 else:
4961 fRc = reporter.error('No progress object returned');
4962
4963 oCurTest.closeSession();
4964 if fRc is oCurRes.fRc:
4965 if fRc:
4966 ## @todo Verify if Guest Additions were really updated (build, revision, ...).
4967 ## @todo r=bird: Not possible since you're installing the same GAs as before...
4968 ## Maybe check creation dates on certain .sys/.dll/.exe files?
4969 pass;
4970 else:
4971 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc, oCurRes.fRc));
4972 break;
4973
4974 return (fRc, oTxsSession);
4975
4976
4977
4978class tdAddGuestCtrl(vbox.TestDriver): # pylint: disable=too-many-instance-attributes,too-many-public-methods
4979 """
4980 Guest control using VBoxService on the guest.
4981 """
4982
4983 def __init__(self):
4984 vbox.TestDriver.__init__(self);
4985 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
4986 self.asRsrcs = None;
4987 self.fQuick = False; # Don't skip lengthly tests by default.
4988 self.addSubTestDriver(SubTstDrvAddGuestCtrl(self));
4989
4990 #
4991 # Overridden methods.
4992 #
4993 def showUsage(self):
4994 """
4995 Shows the testdriver usage.
4996 """
4997 rc = vbox.TestDriver.showUsage(self);
4998 reporter.log('');
4999 reporter.log('tdAddGuestCtrl Options:');
5000 reporter.log(' --quick');
5001 reporter.log(' Same as --virt-modes hwvirt --cpu-counts 1.');
5002 return rc;
5003
5004 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
5005 """
5006 Parses the testdriver arguments from the command line.
5007 """
5008 if asArgs[iArg] == '--quick':
5009 self.parseOption(['--virt-modes', 'hwvirt'], 0);
5010 self.parseOption(['--cpu-counts', '1'], 0);
5011 self.fQuick = True;
5012 else:
5013 return vbox.TestDriver.parseOption(self, asArgs, iArg);
5014 return iArg + 1;
5015
5016 def actionConfig(self):
5017 if not self.importVBoxApi(): # So we can use the constant below.
5018 return False;
5019
5020 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT;
5021 sGaIso = self.getGuestAdditionsIso();
5022 return self.oTestVmSet.actionConfig(self, eNic0AttachType = eNic0AttachType, sDvdImage = sGaIso);
5023
5024 def actionExecute(self):
5025 return self.oTestVmSet.actionExecute(self, self.testOneCfg);
5026
5027 #
5028 # Test execution helpers.
5029 #
5030 def testOneCfg(self, oVM, oTestVm): # pylint: disable=too-many-statements
5031 """
5032 Runs the specified VM thru the tests.
5033
5034 Returns a success indicator on the general test execution. This is not
5035 the actual test result.
5036 """
5037
5038 self.logVmInfo(oVM);
5039
5040 fRc = True;
5041 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName, fCdWait = False);
5042 reporter.log("TxsSession: %s" % (oTxsSession,));
5043 if oSession is not None:
5044 self.addTask(oTxsSession);
5045
5046 fRc, oTxsSession = self.aoSubTstDrvs[0].testIt(oTestVm, oSession, oTxsSession);
5047
5048 # Cleanup.
5049 self.removeTask(oTxsSession);
5050 if not self.aoSubTstDrvs[0].oDebug.fNoExit:
5051 self.terminateVmBySession(oSession);
5052 else:
5053 fRc = False;
5054 return fRc;
5055
5056 def onExit(self, iRc):
5057 if self.aoSubTstDrvs[0].oDebug.fNoExit:
5058 return True
5059 return vbox.TestDriver.onExit(self, iRc);
5060
5061 def gctrlReportError(self, progress):
5062 """
5063 Helper function to report an error of a
5064 given progress object.
5065 """
5066 if progress is None:
5067 reporter.log('No progress object to print error for');
5068 else:
5069 errInfo = progress.errorInfo;
5070 if errInfo:
5071 reporter.log('%s' % (errInfo.text,));
5072 return False;
5073
5074 def gctrlGetRemainingTime(self, msTimeout, msStart):
5075 """
5076 Helper function to return the remaining time (in ms)
5077 based from a timeout value and the start time (both in ms).
5078 """
5079 if msTimeout == 0:
5080 return 0xFFFFFFFE; # Wait forever.
5081 msElapsed = base.timestampMilli() - msStart;
5082 if msElapsed > msTimeout:
5083 return 0; # No time left.
5084 return msTimeout - msElapsed;
5085
5086 def testGuestCtrlManual(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements,unused-argument,unused-variable
5087 """
5088 For manually testing certain bits.
5089 """
5090
5091 reporter.log('Manual testing ...');
5092 fRc = True;
5093
5094 sUser = 'Administrator';
5095 sPassword = 'password';
5096
5097 oGuest = oSession.o.console.guest;
5098 oGuestSession = oGuest.createSession(sUser,
5099 sPassword,
5100 "", "Manual Test");
5101
5102 aWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
5103 _ = oGuestSession.waitForArray(aWaitFor, 30 * 1000);
5104
5105 sCmd = SubTstDrvAddGuestCtrl.getGuestSystemShell(oTestVm);
5106 asArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
5107 aEnv = [];
5108 afFlags = [];
5109
5110 for _ in xrange(100):
5111 oProc = oGuestSession.processCreate(sCmd, asArgs if self.fpApiVer >= 5.0 else asArgs[1:],
5112 aEnv, afFlags, 30 * 1000);
5113
5114 aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
5115 _ = oProc.waitForArray(aWaitFor, 30 * 1000);
5116
5117 oGuestSession.close();
5118 oGuestSession = None;
5119
5120 time.sleep(5);
5121
5122 oSession.o.console.PowerDown();
5123
5124 return (fRc, oTxsSession);
5125
5126if __name__ == '__main__':
5127 sys.exit(tdAddGuestCtrl().main(sys.argv));
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette