VirtualBox

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

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

Validation Kit/tdAddGuestCtrl.py: Simplified long arguments tests.

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

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