VirtualBox

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

Last change on this file since 109278 was 109278, checked in by vboxsync, 9 days ago

Validation Kit/testdriver: Fixed usage of getGuestAdditionsRevision().

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