VirtualBox

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

Last change on this file since 93140 was 93140, checked in by vboxsync, 3 years ago

Validation Kit/Guest Control: Handle guest session closing on guest reboot more gracefully (and log so if it failed).

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

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