VirtualBox

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

Last change on this file since 103892 was 103238, checked in by vboxsync, 13 months ago

Validation Kit/tdAddGuestCtrl.py: More tweaks for older versions and guest OSes needed. bugref:10586

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 289.0 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-2023 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: 103238 $"
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 guests we always can enable verbose logging. NT4 and W2K doesn't have reg.exe nor (at least NT4) sc.exe.
1733 if oTestVm.isWindows() and oTestVm.sKind not in ('WindowsNT4', 'Windows2000',):
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 # Some older Linux test VMs (like tst-rhel5) don't have a pre-configured 'vbox' user.
1743 # So make sure that this user exists and has the appropriate password set. Ignore any errors.
1744 if oTestVm.isLinux():
1745 sCmdUserAdd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr'), 'useradd');
1746 asArgs = [ sCmdUserAdd, '-m', 'vbox' ];
1747 self.oTstDrv.txsRunTest(oTxsSession, sCmdUserAdd, 5 * 60 * 1000, sCmdUserAdd, asArgs,
1748 fCheckSessionStatus = False);
1749 # We must supply the password in an encrypted form using chpasswd (via stdin).
1750 sCmdChPasswd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr'), 'chpasswd');
1751 asArgs = [ sCmdChPasswd ];
1752 self.oTstDrv.txsRunTestStdIn(oTxsSession, sCmdChPasswd, 5 * 60 * 1000, sCmdChPasswd, asArgs,
1753 sStdIn = 'vbox:password\n', fIgnoreErrors = True);
1754
1755 #
1756 # Enable VBoxService verbose logging.
1757 #
1758 reporter.log('Enabling verbose VBoxService logging: %s' % (fEnableVerboseLogging));
1759 if fEnableVerboseLogging:
1760 self.oDebug.sGstVBoxServiceLogPath = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), "VBoxService");
1761 if oTxsSession.syncMkDirPath(self.oDebug.sGstVBoxServiceLogPath, 0o777) is not True:
1762 return reporter.error('Failed to create directory "%s"!' % (self.oDebug.sGstVBoxServiceLogPath,));
1763 sPathLogFile = oTestVm.pathJoin(self.oDebug.sGstVBoxServiceLogPath, 'VBoxService.log');
1764
1765 reporter.log('VBoxService logs will be stored in "%s"' % (self.oDebug.sGstVBoxServiceLogPath,));
1766
1767 fRestartVBoxService = False;
1768 if oTestVm.isWindows() and oTestVm.sKind not in ('WindowsNT4', 'Windows2000',):
1769 sPathRegExe = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'reg.exe');
1770 sImagePath = '%s -vvvv --logfile %s' % (self.sPathVBoxServiceExeGst, sPathLogFile);
1771 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging (via registry)',
1772 30 * 1000,
1773 sPathRegExe,
1774 (sPathRegExe, 'add',
1775 'HKLM\\SYSTEM\\CurrentControlSet\\Services\\VBoxService',
1776 '/v', 'ImagePath', '/t', 'REG_SZ', '/d', sImagePath, '/f'));
1777 elif oTestVm.isLinux():
1778 sPathSed = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'sed');
1779 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging', 30 * 1000,
1780 sPathSed,
1781 (sPathSed, '-i', '-e', 's/'
1782 '\\$2 \\$3'
1783 '/'
1784 '\\$2 \\$3 -vvvv --logfile \\/var\\/tmp\\/VBoxService\\/VBoxService.log'
1785 '/g',
1786 '/sbin/rcvboxadd-service'));
1787 else:
1788 reporter.log('Verbose logging for VBoxService not supported for this guest yet');
1789
1790 if fRestartVBoxService:
1791 # Wait for VBoxService to start up properly so, we can shut it down again and restart.
1792 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1793 vboxcon.AdditionsFacilityStatus_Active);
1794 if not fRc:
1795 reporter.log('VBoxService didn\'t startup in time');
1796 return False;
1797
1798 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1799 self.oTstDrv.sleep(5);
1800 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1801
1802 # Wait for VBoxService to start up in any case.
1803 reporter.testStart('Waiting for VBoxService to get started');
1804 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1805 vboxcon.AdditionsFacilityStatus_Active);
1806 reporter.testDone();
1807 if not fRc:
1808 return False;
1809
1810 #
1811 # Generate and upload some random files and dirs to the guest.
1812 # Note! Make sure we don't run into too-long-path issues when using
1813 # the test files on the host if.
1814 #
1815 cchGst = len(self.oTstDrv.getGuestTempDir(oTestVm)) + 1 + len('addgst-1') + 1;
1816 cchHst = len(self.oTstDrv.sScratchPath) + 1 + len('copyto/addgst-1') + 1;
1817 cchMaxPath = 230;
1818 if cchHst > cchGst:
1819 cchMaxPath -= cchHst - cchGst;
1820 reporter.log('cchMaxPath=%s (cchHst=%s, cchGst=%s)' % (cchMaxPath, cchHst, cchGst,));
1821 self.oTestFiles = vboxtestfileset.TestFileSet(oTestVm,
1822 self.oTstDrv.getGuestTempDir(oTestVm), 'addgst-1',
1823 # Make sure that we use a lowest common denominator across all supported
1824 # platforms, to make testing the randomly generated file paths work
1825 # reliably.
1826 cchMaxPath = cchMaxPath, asCompatibleWith = [ ('cross') ]);
1827 return self.oTestFiles.upload(oTxsSession, self.oTstDrv);
1828
1829
1830 #
1831 # gctrlXxxx stuff.
1832 #
1833
1834 def gctrlCopyFileFrom(self, oGuestSession, oTest, fExpected):
1835 """
1836 Helper function to copy a single file from the guest to the host.
1837 """
1838
1839 # As we pass-in randomly generated file names, the source sometimes can be empty, which
1840 # in turn will result in a (correct) error by the API. Simply skip this function then.
1841 if not oTest.sSrc:
1842 reporter.log2('Skipping guest file "%s"' % (limitString(oTest.sSrc)));
1843 return fExpected;
1844
1845 #
1846 # Do the copying.
1847 #
1848 reporter.log2('Copying guest file "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1849 try:
1850 if self.oTstDrv.fpApiVer >= 5.0:
1851 oCurProgress = oGuestSession.fileCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1852 else:
1853 oCurProgress = oGuestSession.copyFrom(oTest.sSrc, oTest.sDst, oTest.afFlags);
1854 except:
1855 reporter.maybeErrXcpt(fExpected, 'Copy from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1856 return False;
1857 if oCurProgress is None:
1858 return reporter.error('No progress object returned');
1859 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlFileCopyFrom");
1860 oProgress.wait();
1861 if not oProgress.isSuccess():
1862 oProgress.logResult(fIgnoreErrors = not fExpected);
1863 return False;
1864
1865 #
1866 # Check the result if we can.
1867 #
1868 if oTest.oSrc:
1869 assert isinstance(oTest.oSrc, testfileset.TestFile);
1870 sDst = oTest.sDst;
1871 if os.path.isdir(sDst):
1872 sDst = os.path.join(sDst, oTest.oSrc.sName);
1873 try:
1874 oFile = open(sDst, 'rb'); # pylint: disable=consider-using-with
1875 except:
1876 # Don't report expected non-existing paths / files as an error.
1877 return reporter.maybeErrXcpt(fExpected, 'open(%s) failed during verfication (file / path not found)' % (sDst,));
1878 fEqual = oTest.oSrc.equalFile(oFile);
1879 oFile.close();
1880 if not fEqual:
1881 return reporter.error('Content differs for "%s"' % (sDst,));
1882
1883 return True;
1884
1885 def __compareTestDir(self, oDir, sHostPath): # type: (testfileset.TestDir, str) -> bool
1886 """
1887 Recursively compare the content of oDir and sHostPath.
1888
1889 Returns True on success, False + error logging on failure.
1890
1891 Note! This ASSUMES that nothing else was copied to sHostPath!
1892 """
1893 #
1894 # First check out all the entries and files in the directory.
1895 #
1896 dLeftUpper = dict(oDir.dChildrenUpper);
1897 try:
1898 asEntries = os.listdir(sHostPath);
1899 except:
1900 return reporter.errorXcpt('os.listdir(%s) failed' % (sHostPath,));
1901
1902 fRc = True;
1903 for sEntry in asEntries:
1904 sEntryUpper = sEntry.upper();
1905 if sEntryUpper not in dLeftUpper:
1906 fRc = reporter.error('Unexpected entry "%s" in "%s"' % (sEntry, sHostPath,));
1907 else:
1908 oFsObj = dLeftUpper[sEntryUpper];
1909 del dLeftUpper[sEntryUpper];
1910
1911 if isinstance(oFsObj, testfileset.TestFile):
1912 sFilePath = os.path.join(sHostPath, oFsObj.sName);
1913 try:
1914 oFile = open(sFilePath, 'rb'); # pylint: disable=consider-using-with
1915 except:
1916 fRc = reporter.errorXcpt('open(%s) failed during verfication' % (sFilePath,));
1917 else:
1918 fEqual = oFsObj.equalFile(oFile);
1919 oFile.close();
1920 if not fEqual:
1921 fRc = reporter.error('Content differs for "%s"' % (sFilePath,));
1922
1923 # List missing entries:
1924 for sKey in dLeftUpper:
1925 oEntry = dLeftUpper[sKey];
1926 fRc = reporter.error('%s: Missing %s "%s" (src path: %s)'
1927 % (sHostPath, oEntry.sName,
1928 'file' if isinstance(oEntry, testfileset.TestFile) else 'directory', oEntry.sPath));
1929
1930 #
1931 # Recurse into subdirectories.
1932 #
1933 for oFsObj in oDir.aoChildren:
1934 if isinstance(oFsObj, testfileset.TestDir):
1935 fRc = self.__compareTestDir(oFsObj, os.path.join(sHostPath, oFsObj.sName)) and fRc;
1936 return fRc;
1937
1938 def gctrlCopyDirFrom(self, oGuestSession, oTest, fExpected):
1939 """
1940 Helper function to copy a directory from the guest to the host.
1941 """
1942
1943 # As we pass-in randomly generated directories, the source sometimes can be empty, which
1944 # in turn will result in a (correct) error by the API. Simply skip this function then.
1945 if not oTest.sSrc:
1946 reporter.log2('Skipping guest dir "%s"' % (limitString(oTest.sSrc)));
1947 return fExpected;
1948
1949 #
1950 # Do the copying.
1951 #
1952 reporter.log2('Copying guest dir "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1953 try:
1954 if self.oTstDrv.fpApiVer >= 7.0:
1955 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
1956 if not oTest.afFlags:
1957 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
1958 elif vboxcon.DirectoryCopyFlag_Recursive not in oTest.afFlags:
1959 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
1960 ## @todo Ditto.
1961 if not oTest.afFlags:
1962 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_FollowLinks, ];
1963 elif vboxcon.DirectoryCopyFlag_FollowLinks not in oTest.afFlags:
1964 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
1965 oCurProgress = oGuestSession.directoryCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1966 except:
1967 reporter.maybeErrXcpt(fExpected, 'Copy dir from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1968 return False;
1969 if oCurProgress is None:
1970 return reporter.error('No progress object returned');
1971
1972 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlDirCopyFrom");
1973 oProgress.wait();
1974 if not oProgress.isSuccess():
1975 oProgress.logResult(fIgnoreErrors = not fExpected);
1976 return False;
1977
1978 #
1979 # Check the result if we can.
1980 #
1981 if oTest.oSrc:
1982 assert isinstance(oTest.oSrc, testfileset.TestDir);
1983 sDst = oTest.sDst;
1984 if oTest.fIntoDst:
1985 return self.__compareTestDir(oTest.oSrc, os.path.join(sDst, oTest.oSrc.sName));
1986 oDummy = testfileset.TestDir(None, 'dummy');
1987 oDummy.aoChildren = [oTest.oSrc,]
1988 oDummy.dChildrenUpper = { oTest.oSrc.sName.upper(): oTest.oSrc, };
1989 return self.__compareTestDir(oDummy, sDst);
1990 return True;
1991
1992 def gctrlCopyFileTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1993 """
1994 Helper function to copy a single file from the host to the guest.
1995
1996 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
1997 """
1998 reporter.log2('Copying host file "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
1999 try:
2000 if self.oTstDrv.fpApiVer >= 5.0:
2001 oCurProgress = oGuestSession.fileCopyToGuest(sSrc, sDst, afFlags);
2002 else:
2003 oCurProgress = oGuestSession.copyTo(sSrc, sDst, afFlags);
2004 except:
2005 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
2006 return False;
2007
2008 if oCurProgress is None:
2009 return reporter.error('No progress object returned');
2010 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
2011
2012 try:
2013 oProgress.wait();
2014 if not oProgress.isSuccess():
2015 oProgress.logResult(fIgnoreErrors = not fIsError);
2016 return False;
2017 except:
2018 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
2019 return False;
2020 return True;
2021
2022 def gctrlCopyDirTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
2023 """
2024 Helper function to copy a directory (tree) from the host to the guest.
2025
2026 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
2027 """
2028 reporter.log2('Copying host directory "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
2029 try:
2030 if self.oTstDrv.fpApiVer >= 7.0:
2031 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
2032 if not afFlags:
2033 afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
2034 elif vboxcon.DirectoryCopyFlag_Recursive not in afFlags:
2035 afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
2036 ## @todo Ditto.
2037 if not afFlags:
2038 afFlags = [vboxcon.DirectoryCopyFlag_FollowLinks,];
2039 elif vboxcon.DirectoryCopyFlag_FollowLinks not in afFlags:
2040 afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
2041 oCurProgress = oGuestSession.directoryCopyToGuest(sSrc, sDst, afFlags);
2042 except:
2043 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
2044 return False;
2045
2046 if oCurProgress is None:
2047 return reporter.error('No progress object returned');
2048 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
2049
2050 try:
2051 oProgress.wait();
2052 if not oProgress.isSuccess():
2053 oProgress.logResult(fIgnoreErrors = not fIsError);
2054 return False;
2055 except:
2056 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
2057 return False;
2058 return True;
2059
2060 def gctrlCreateDir(self, oTest, oRes, oGuestSession):
2061 """
2062 Helper function to create a guest directory specified in the current test.
2063 """
2064 reporter.log2('Creating directory "%s"' % (limitString(oTest.sDirectory),));
2065 try:
2066 oGuestSession.directoryCreate(oTest.sDirectory, oTest.fMode, oTest.afFlags);
2067 except:
2068 reporter.maybeErrXcpt(oRes.fRc, 'Failed to create "%s" fMode=%o afFlags=%s'
2069 % (oTest.sDirectory, oTest.fMode, oTest.afFlags,));
2070 return not oRes.fRc;
2071 if oRes.fRc is not True:
2072 return reporter.error('Did not expect to create directory "%s"!' % (oTest.sDirectory,));
2073
2074 # Check if the directory now exists.
2075 try:
2076 if self.oTstDrv.fpApiVer >= 5.0:
2077 fDirExists = oGuestSession.directoryExists(oTest.sDirectory, False);
2078 else:
2079 fDirExists = oGuestSession.directoryExists(oTest.sDirectory);
2080 except:
2081 return reporter.errorXcpt('directoryExists failed on "%s"!' % (oTest.sDirectory,));
2082 if not fDirExists:
2083 return reporter.errorXcpt('directoryExists returned False on "%s" after directoryCreate succeeded!'
2084 % (oTest.sDirectory,));
2085 return True;
2086
2087 def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, fUseDirList = False, cEntriesPerRead = 0, sSubDir = None):
2088 """
2089 Helper function to recursively read a guest directory tree specified in the current test.
2090 """
2091 sDir = oTest.sDirectory;
2092 sFilter = oTest.sFilter;
2093 afFlags = oTest.afFlags;
2094 oTestVm = oTest.oCreds.oTestVm;
2095 sCurDir = oTestVm.pathJoin(sDir, sSubDir) if sSubDir else sDir;
2096
2097 fRc = True; # Be optimistic.
2098 cDirs = 0; # Number of directories read.
2099 cFiles = 0; # Number of files read.
2100 cOthers = 0; # Other files.
2101
2102 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2103 aFsObjInfo = [];
2104
2105 # Open the directory:
2106 reporter.log2('Directory="%s", filter="%s", afFlags="%s", fUseDirList=%s, cEntriesPerRead=%d'
2107 % (limitString(sCurDir), sFilter, afFlags, fUseDirList, cEntriesPerRead));
2108 try:
2109 oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
2110 except:
2111 reporter.maybeErrXcpt(fIsError, 'sCurDir=%s sFilter=%s afFlags=%s' % (sCurDir, sFilter, afFlags,))
2112 return (False, 0, 0, 0);
2113
2114 # Read the directory.
2115 fDone = False;
2116 while fRc is True:
2117 reporter.log3('Reading next batch ...');
2118 aFsObjInfo = [];
2119 try:
2120 if not fUseDirList:
2121 aFsObjInfo.append(oCurDir.read());
2122 else:
2123 if not cEntriesToRead:
2124 cEntriesToRead = random.randrange(1, 32768);
2125 aFsObjInfo = oCurDir.list(cEntriesToRead);
2126 except Exception as oXcpt:
2127 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2128 if fUseDirList:
2129 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % (sCurDir, cEntriesToRead));
2130 else:
2131 if self.oTstDrv.fpApiVer > 5.2:
2132 reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
2133 else:
2134 # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
2135 reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
2136 fRc = False;
2137 else:
2138 reporter.log2('\tNo more directory entries for "%s"' % (limitString(sCurDir),));
2139 fDone = True;
2140 break;
2141
2142 if fDone or not fRc: # Abort reading?
2143 break;
2144
2145 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2146 for oFsObjInfo in aFsObjInfo:
2147 try:
2148 sName = oFsObjInfo.name;
2149 eType = oFsObjInfo.type;
2150 except:
2151 fRc = reporter.errorXcpt();
2152 break;
2153
2154 if sName in ('.', '..', ):
2155 if eType != vboxcon.FsObjType_Directory:
2156 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2157 % (sName, eType, vboxcon.FsObjType_Directory));
2158 elif eType == vboxcon.FsObjType_Directory:
2159 reporter.log2(' Directory "%s"' % limitString(oFsObjInfo.name));
2160 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
2161 fUseDirList, cEntriesPerRead,
2162 oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
2163 fRc = aSubResult[0];
2164 cDirs += aSubResult[1] + 1;
2165 cFiles += aSubResult[2];
2166 cOthers += aSubResult[3];
2167 elif eType is vboxcon.FsObjType_File:
2168 reporter.log4(' File "%s"' % oFsObjInfo.name);
2169 cFiles += 1;
2170 elif eType is vboxcon.FsObjType_Symlink:
2171 reporter.log4(' Symlink "%s" -- not tested yet' % oFsObjInfo.name);
2172 cOthers += 1;
2173 elif oTestVm.isWindows() \
2174 or oTestVm.isOS2() \
2175 or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
2176 vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
2177 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
2178 (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
2179 else:
2180 cOthers += 1;
2181
2182 # Close the directory
2183 try:
2184 oCurDir.close();
2185 except:
2186 fRc = reporter.errorXcpt('sCurDir=%s' % (sCurDir));
2187
2188 return (fRc, cDirs, cFiles, cOthers);
2189
2190 def gctrlReadDirTree2(self, oGuestSession, oDir, fUseDirList = False, cEntriesPerRead = 0):
2191 # type: (testfileset.TestDir) -> bool
2192 """
2193 Helper function to recursively read a guest directory tree specified in the current test.
2194 """
2195
2196 #
2197 # Process the directory.
2198 #
2199
2200 # Open the directory:
2201 try:
2202 oCurDir = oGuestSession.directoryOpen(oDir.sPath, '', None);
2203 except:
2204 return reporter.errorXcpt('sPath=%s' % (oDir.sPath,));
2205
2206 # Read the directory.
2207 dLeftUpper = dict(oDir.dChildrenUpper);
2208 cDot = 0;
2209 cDotDot = 0;
2210 fRc = True;
2211 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2212 aFsObjInfo = [];
2213 while True:
2214 reporter.log3('Reading next batch ...');
2215 aFsObjInfo = [];
2216 try:
2217 if not fUseDirList:
2218 aFsObjInfo.append(oCurDir.read());
2219 else:
2220 if not cEntriesToRead:
2221 cEntriesToRead = random.randrange(1, 32768);
2222 aFsObjInfo = oCurDir.list(cEntriesToRead);
2223 except Exception as oXcpt:
2224 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2225 if fUseDirList:
2226 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % \
2227 (oDir.sPath, cEntriesToRead));
2228 else:
2229 fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath));
2230 else:
2231 reporter.log2('\tNo more directory entries for "%s"' % (limitString(oDir.sPath),));
2232 break;
2233
2234 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2235 for oFsObjInfo in aFsObjInfo:
2236 try:
2237 sName = oFsObjInfo.name;
2238 eType = oFsObjInfo.type;
2239 cbFile = oFsObjInfo.objectSize;
2240 ## @todo check further attributes.
2241 except:
2242 fRc = reporter.errorXcpt();
2243 break;
2244
2245 # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
2246 if sName in ('.', '..', ):
2247 if eType != vboxcon.FsObjType_Directory:
2248 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2249 % (sName, eType, vboxcon.FsObjType_Directory));
2250 if sName == '.': cDot += 1;
2251 else: cDotDot += 1;
2252 else:
2253 # Find the child and remove it from the dictionary.
2254 sNameUpper = sName.upper();
2255 oFsObj = dLeftUpper.get(sNameUpper);
2256 if oFsObj is None:
2257 fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
2258 % (sName, oDir.sPath, eType, cbFile,));
2259 else:
2260 del dLeftUpper[sNameUpper];
2261
2262 # Check type
2263 if isinstance(oFsObj, testfileset.TestDir):
2264 if eType != vboxcon.FsObjType_Directory:
2265 fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
2266 % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
2267 elif isinstance(oFsObj, testfileset.TestFile):
2268 if eType != vboxcon.FsObjType_File:
2269 fRc = reporter.error('%s: expected file (%d), got eType=%d!'
2270 % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
2271 else:
2272 fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
2273
2274 # Check the name.
2275 if oFsObj.sName != sName:
2276 fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % \
2277 (oFsObj.sPath, oFsObj.sName, sName,));
2278
2279 # Check the size if a file.
2280 if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
2281 fRc = reporter.error('%s: expected size %s, got %s instead!' % \
2282 (oFsObj.sPath, oFsObj.cbContent, cbFile,));
2283
2284 ## @todo check timestamps and attributes.
2285
2286 # Close the directory
2287 try:
2288 oCurDir.close();
2289 except:
2290 fRc = reporter.errorXcpt('oDir.sPath=%s' % (oDir.sPath,));
2291
2292 # Any files left over?
2293 for sKey in dLeftUpper:
2294 oFsObj = dLeftUpper[sKey];
2295 fRc = reporter.error('%s: Was not returned! (%s)' % (oFsObj.sPath, type(oFsObj),));
2296
2297 # Check the dot and dot-dot counts.
2298 if cDot != 1:
2299 fRc = reporter.error('%s: Found %s "." entries, expected exactly 1!' % (oDir.sPath, cDot,));
2300 if cDotDot != 1:
2301 fRc = reporter.error('%s: Found %s ".." entries, expected exactly 1!' % (oDir.sPath, cDotDot,));
2302
2303 #
2304 # Recurse into subdirectories using info from oDir.
2305 #
2306 for oFsObj in oDir.aoChildren:
2307 if isinstance(oFsObj, testfileset.TestDir):
2308 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj, fUseDirList, cEntriesPerRead) and fRc;
2309
2310 return fRc;
2311
2312 def gctrlExecDoTest(self, i, oTest, oRes, oGuestSession):
2313 """
2314 Wrapper function around gctrlExecute to provide more sanity checking
2315 when needed in actual execution tests.
2316 """
2317 reporter.log('Testing #%d, cmd="%s" ...' % (i, oTest.sCmd));
2318 fRcExec = self.gctrlExecute(oTest, oGuestSession, oRes.fRc);
2319 if fRcExec == oRes.fRc:
2320 fRc = True;
2321 if fRcExec is True:
2322 # Compare exit status / code on successful process execution.
2323 if oTest.uExitStatus != oRes.uExitStatus \
2324 or oTest.iExitCode != oRes.iExitCode:
2325 fRc = reporter.error('Test #%d (%s) failed: Got exit status + code %d,%d, expected %d,%d'
2326 % (i, oTest.asArgs, oTest.uExitStatus, oTest.iExitCode,
2327 oRes.uExitStatus, oRes.iExitCode));
2328
2329 # Compare test / result buffers on successful process execution.
2330 if oTest.sBuf is not None and oRes.sBuf is not None:
2331 if not utils.areBytesEqual(oTest.sBuf, oRes.sBuf):
2332 fRc = reporter.error('Test #%d (%s) failed: Got buffer\n%s (%d bytes), expected\n%s (%d bytes)'
2333 % (i, oTest.asArgs,
2334 map(hex, map(ord, oTest.sBuf)), len(oTest.sBuf),
2335 map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf)));
2336 reporter.log2('Test #%d passed: Buffers match (%d bytes)' % (i, len(oRes.sBuf)));
2337 elif oRes.sBuf and not oTest.sBuf:
2338 fRc = reporter.error('Test #%d (%s) failed: Got no buffer data, expected\n%s (%dbytes)' %
2339 (i, oTest.asArgs, map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf),));
2340
2341 if oRes.cbStdOut is not None and oRes.cbStdOut != oTest.cbStdOut:
2342 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stdout data, expected %d'
2343 % (i, oTest.asArgs, oTest.cbStdOut, oRes.cbStdOut));
2344 if oRes.cbStdErr is not None and oRes.cbStdErr != oTest.cbStdErr:
2345 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stderr data, expected %d'
2346 % (i, oTest.asArgs, oTest.cbStdErr, oRes.cbStdErr));
2347 else:
2348 fRc = reporter.error('Test #%d (%s) failed: Got %s, expected %s' % (i, oTest.asArgs, fRcExec, oRes.fRc));
2349 return fRc;
2350
2351 def processCreateWrapper(self, oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS):
2352 """
2353 Wrapepr function to deal with different flavors of the IGuestProcess::processCreate call,
2354 depending on the API version.
2355
2356 Returns oProcess object on success, None on failure.
2357 """
2358 oProcess = None;
2359
2360 reporter.log2('Executing sCmd=%s, cCwd=%s, afFlags=%s, timeoutMS=%d, asArgs=%s, asEnv=%s'
2361 % (sCmd, sCwd, afFlags, timeoutMS, limitString(asArgs), limitString(aEnv),));
2362
2363 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485:
2364 # 7.1 adds a current working directory parameter.
2365 oProcess = oGuestSession.processCreate(sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS);
2366 else:
2367 oProcess = oGuestSession.processCreate(sCmd,
2368 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2369 aEnv, afFlags, timeoutMS);
2370 return oProcess;
2371
2372 def processExecute(self, oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS, fIsError = True):
2373 """
2374 Executes a process on the guest and deals with input/output + waiting flags.
2375
2376 Returns tuple (success, exit status, exit code, stdout len, stderr len, stdout / stderr output).
2377 """
2378
2379 #
2380 # Start the process:
2381 #
2382 try:
2383 oProcess = self.processCreateWrapper(oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS);
2384 except:
2385 reporter.maybeErrXcpt(fIsError, 'type=%s, asArgs=%s' % (type(asArgs), asArgs,));
2386 return (False, vboxcon.ProcessStatus_Undefined, 0, 0, 0, '');
2387 if oProcess is None:
2388 reporter.error('oProcess is None! (%s)' % (asArgs,));
2389 return (False, vboxcon.ProcessStatus_Undefined, 0, 0, 0, '');
2390
2391 fRc = True;
2392 uExitStatus = vboxcon.ProcessStatus_Undefined;
2393 iExitCode = -1;
2394 cbStdOut = 0;
2395 cbStdErr = 0;
2396 sBufOut = '';
2397
2398 #time.sleep(5); # try this if you want to see races here.
2399
2400 # Wait for the process to start properly:
2401 reporter.log2('Process start requested, waiting for start (%dms) ...' % (timeoutMS,));
2402 iPid = -1;
2403 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Start, ];
2404 try:
2405 eWaitResult = oProcess.waitForArray(aeWaitFor, timeoutMS);
2406 except:
2407 reporter.maybeErrXcpt(fIsError, 'waitforArray failed for asArgs=%s' % (asArgs,));
2408 fRc = False;
2409 else:
2410 try:
2411 eStatus = oProcess.status;
2412 iPid = oProcess.PID;
2413 except:
2414 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2415 else:
2416 reporter.log2('Wait result returned: %d, current process status is: %d' % (eWaitResult, eStatus,));
2417
2418 #
2419 # Wait for the process to run to completion if necessary.
2420 #
2421 # Note! The above eWaitResult return value can be ignored as it will
2422 # (mostly) reflect the process status anyway.
2423 #
2424 if eStatus == vboxcon.ProcessStatus_Started:
2425
2426 # What to wait for:
2427 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, ];
2428 if vboxcon.ProcessCreateFlag_WaitForStdOut in afFlags:
2429 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdOut);
2430 if vboxcon.ProcessCreateFlag_WaitForStdErr in afFlags:
2431 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdErr);
2432 ## @todo Add vboxcon.ProcessWaitForFlag_StdIn.
2433
2434 reporter.log2('Process (PID %d) started, waiting for termination (%dms), aeWaitFor=%s ...'
2435 % (iPid, timeoutMS, aeWaitFor));
2436 acbFdOut = [0,0,0];
2437 while True:
2438 try:
2439 eWaitResult = oProcess.waitForArray(aeWaitFor, timeoutMS);
2440 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2441 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2442 try: oProcess.close();
2443 except: pass;
2444 break;
2445 except:
2446 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2447 break;
2448 #reporter.log2('Wait returned: %d' % (eWaitResult,));
2449
2450 # Process output:
2451 for eFdResult, iFd, sFdNm in [ (vboxcon.ProcessWaitResult_StdOut, 1, 'stdout'),
2452 (vboxcon.ProcessWaitResult_StdErr, 2, 'stderr'), ]:
2453 if eWaitResult in (eFdResult, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2454 try:
2455 abBuf = oProcess.read(iFd, 64 * 1024, timeoutMS);
2456 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2457 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2458 try: oProcess.close();
2459 except: pass;
2460 except:
2461 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (asArgs,));
2462 else:
2463 if abBuf:
2464 reporter.log2('Process (PID %d) got %d bytes of %s data (type: %s)'
2465 % (iPid, len(abBuf), sFdNm, type(abBuf)));
2466 if reporter.getVerbosity() >= 4:
2467 sBufOut = '';
2468 if sys.version_info >= (2, 7):
2469 if isinstance(abBuf, memoryview): ## @todo Why is this happening?
2470 abBuf = abBuf.tobytes();
2471 sBufOut = abBuf.decode("utf-8");
2472 if sys.version_info <= (2, 7):
2473 if isinstance(abBuf, buffer): # (for 3.0+) pylint: disable=undefined-variable
2474 sBufOut = str(abBuf);
2475 for sLine in sBufOut.splitlines():
2476 reporter.log4('%s: %s' % (sFdNm, sLine));
2477 acbFdOut[iFd] += len(abBuf);
2478 sBufOut = abBuf; ## @todo Figure out how to uniform + append!
2479
2480 ## Process input (todo):
2481 #if eWaitResult in (vboxcon.ProcessWaitResult_StdIn, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2482 # reporter.log2('Process (PID %d) needs stdin data' % (iPid,));
2483
2484 # Termination or error?
2485 if eWaitResult in (vboxcon.ProcessWaitResult_Terminate,
2486 vboxcon.ProcessWaitResult_Error,
2487 vboxcon.ProcessWaitResult_Timeout,):
2488 try: eStatus = oProcess.status;
2489 except: fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2490 reporter.log2('Process (PID %d) reported terminate/error/timeout: %d, status: %d'
2491 % (iPid, eWaitResult, eStatus,));
2492 break;
2493
2494 # End of the wait loop.
2495 _, cbStdOut, cbStdErr = acbFdOut;
2496
2497 try: eStatus = oProcess.status;
2498 except: fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2499 reporter.log2('Final process status (PID %d) is: %d' % (iPid, eStatus));
2500 reporter.log2('Process (PID %d) %d stdout, %d stderr' % (iPid, cbStdOut, cbStdErr));
2501
2502 #
2503 # Get the final status and exit code of the process.
2504 #
2505 try:
2506 uExitStatus = oProcess.status;
2507 iExitCode = oProcess.exitCode;
2508 except:
2509 fRc = reporter.errorXcpt('asArgs=%s' % (asArgs,));
2510 reporter.log2('Process (PID %d) has exit code: %d; status: %d ' % (iPid, iExitCode, uExitStatus));
2511 return (fRc, uExitStatus, iExitCode, cbStdOut, cbStdErr, sBufOut);
2512
2513 def gctrlExecute(self, oTest, oGuestSession, fIsError): # pylint: disable=too-many-statements
2514 """
2515 Helper function to execute a program on a guest, specified in the current test.
2516
2517 Note! This weirdo returns results (process exitcode and status) in oTest.
2518 """
2519 fRc = True; # Be optimistic.
2520
2521 # Reset the weird result stuff:
2522 oTest.cbStdOut = 0;
2523 oTest.cbStdErr = 0;
2524 oTest.sBuf = '';
2525 oTest.uExitStatus = 0;
2526 oTest.iExitCode = 0;
2527
2528 ## @todo Compare execution timeouts!
2529 #tsStart = base.timestampMilli();
2530
2531 try:
2532 reporter.log2('Using session user=%s, sDomain=%s, name=%s, timeout=%d'
2533 % (oGuestSession.user, oGuestSession.domain, oGuestSession.name, oGuestSession.timeout,));
2534 except:
2535 return reporter.errorXcpt();
2536
2537 fRc, oTest.uExitStatus, oTest.iExitCode, oTest.cbStdOut, oTest.cbStdErr, oTest.sBuf = \
2538 self.processExecute(oGuestSession, oTest.sCmd, oTest.asArgs, oTest.sCwd, \
2539 oTest.aEnv, oTest.afFlags, oTest.timeoutMS, fIsError);
2540
2541 return fRc;
2542
2543 def executeGstCtlHelper(self, oTxsSession, oGuestSession, asArgs, asEnv = None, sCwd = '', timeoutMS = 30 * 1000):
2544 """
2545 Wrapper to invoke the Guest Control Helper on the guest.
2546
2547 Returns tuple (success, exit status, exit code, stdout len, stderr len, stdout / stderr output).
2548 """
2549 fRc = True;
2550 eExitStatus = vboxcon.ProcessStatus_Undefined;
2551 iExitCode = -1;
2552 cbStdOut = 0;
2553 cbStdErr = 0;
2554 sBuf = '';
2555
2556 if not self.sGstCtlHelperExe:
2557 fRc, self.sGstCtlHelperExe = self.locateGstBinary(oTxsSession, self.asGstCtlHelperPaths);
2558 if fRc:
2559 reporter.log('Using VBoxGuestControlHelper on guest at \"%s\"' % (self.sGstCtlHelperExe));
2560
2561 if fRc \
2562 and self.sGstCtlHelperExe:
2563 try:
2564 asArgs2 = [ self.sGstCtlHelperExe ]; # Always set argv0.
2565 asArgs2.extend(asArgs); # Add the arguments passed-in.
2566 if not asEnv:
2567 asEnv = [];
2568 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, \
2569 vboxcon.ProcessWaitForFlag_StdOut, \
2570 vboxcon.ProcessWaitForFlag_StdErr ];
2571
2572 fRc, eExitStatus, iExitCode, cbStdOut, cbStdErr, sBuf = \
2573 self.processExecute(oGuestSession, self.sGstCtlHelperExe, asArgs2, sCwd, \
2574 asEnv, aeWaitFor, timeoutMS);
2575 if eExitStatus != vboxcon.ProcessStatus_TerminatedNormally:
2576 reporter.log('VBoxGuestControlHelper failed to run; got exit status %d' % (eExitStatus,));
2577 fRc = False;
2578 except:
2579 fRc = reporter.errorXcpt();
2580
2581 return (fRc, eExitStatus, iExitCode, cbStdOut, cbStdErr, sBuf);
2582
2583 def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2584 """
2585 Tests the guest session environment changes.
2586 """
2587 aoTests = [
2588 # Check basic operations.
2589 tdTestSessionEx([ # Initial environment is empty.
2590 tdStepSessionCheckEnv(),
2591 # Check clearing empty env.
2592 tdStepSessionClearEnv(),
2593 tdStepSessionCheckEnv(),
2594 # Check set.
2595 tdStepSessionSetEnv('FOO', 'BAR'),
2596 tdStepSessionCheckEnv(['FOO=BAR',]),
2597 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2598 tdStepSessionClearEnv(),
2599 tdStepSessionCheckEnv(),
2600 # Check unset.
2601 tdStepSessionUnsetEnv('BAR'),
2602 tdStepSessionCheckEnv(['BAR']),
2603 tdStepSessionClearEnv(),
2604 tdStepSessionCheckEnv(),
2605 # Set + unset.
2606 tdStepSessionSetEnv('FOO', 'BAR'),
2607 tdStepSessionCheckEnv(['FOO=BAR',]),
2608 tdStepSessionUnsetEnv('FOO'),
2609 tdStepSessionCheckEnv(['FOO']),
2610 # Bulk environment changes (via attrib) (shall replace existing 'FOO').
2611 tdStepSessionBulkEnv( ['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2612 tdStepSessionCheckEnv(['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2613 ]),
2614 tdTestSessionEx([ # Check that setting the same value several times works.
2615 tdStepSessionSetEnv('FOO','BAR'),
2616 tdStepSessionCheckEnv([ 'FOO=BAR',]),
2617 tdStepSessionSetEnv('FOO','BAR2'),
2618 tdStepSessionCheckEnv([ 'FOO=BAR2',]),
2619 tdStepSessionSetEnv('FOO','BAR3'),
2620 tdStepSessionCheckEnv([ 'FOO=BAR3',]),
2621 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2622 # Add a little unsetting to the mix.
2623 tdStepSessionSetEnv('BAR', 'BEAR'),
2624 tdStepSessionCheckEnv([ 'FOO=BAR3', 'BAR=BEAR',]),
2625 tdStepSessionUnsetEnv('FOO'),
2626 tdStepSessionCheckEnv([ 'FOO', 'BAR=BEAR',]),
2627 tdStepSessionSetEnv('FOO','BAR4'),
2628 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR',]),
2629 # The environment is case sensitive.
2630 tdStepSessionSetEnv('foo','BAR5'),
2631 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo=BAR5']),
2632 tdStepSessionUnsetEnv('foo'),
2633 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo']),
2634 ]),
2635 tdTestSessionEx([ # Bulk settings merges stuff, last entry standing.
2636 tdStepSessionBulkEnv(['FOO=bar', 'foo=bar', 'FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2637 tdStepSessionCheckEnv(['FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2638 tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2639 tdStepSessionBulkEnv(['2=1+1', 'FOO=doofus2', ]),
2640 tdStepSessionCheckEnv(['2=1+1', 'FOO=doofus2' ]),
2641 ]),
2642 # Invalid variable names.
2643 tdTestSessionEx([
2644 tdStepSessionSetEnv('', 'FOO', vbox.ComError.E_INVALIDARG),
2645 tdStepSessionCheckEnv(),
2646 tdStepRequireMinimumApiVer(5.0), # 4.3 is too relaxed checking input!
2647 tdStepSessionBulkEnv(['', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2648 tdStepSessionCheckEnv(),
2649 tdStepSessionSetEnv('FOO=', 'BAR', vbox.ComError.E_INVALIDARG),
2650 tdStepSessionCheckEnv(),
2651 ]),
2652 # A bit more weird keys/values.
2653 tdTestSessionEx([ tdStepSessionSetEnv('$$$', ''),
2654 tdStepSessionCheckEnv([ '$$$=',]), ]),
2655 tdTestSessionEx([ tdStepSessionSetEnv('$$$', '%%%'),
2656 tdStepSessionCheckEnv([ '$$$=%%%',]),
2657 ]),
2658 tdTestSessionEx([ tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2659 tdStepSessionSetEnv(u'ß$%ß&', ''),
2660 tdStepSessionCheckEnv([ u'ß$%ß&=',]),
2661 ]),
2662 # Misc stuff.
2663 tdTestSessionEx([ tdStepSessionSetEnv('FOO', ''),
2664 tdStepSessionCheckEnv(['FOO=',]),
2665 ]),
2666 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2667 tdStepSessionCheckEnv(['FOO=BAR',])
2668 ],),
2669 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2670 tdStepSessionSetEnv('BAR', 'BAZ'),
2671 tdStepSessionCheckEnv([ 'FOO=BAR', 'BAR=BAZ',]),
2672 ]),
2673 ];
2674 # Leading '=' in the name is okay for windows guests in 6.1 and later (for driver letter CWDs).
2675 if (self.oTstDrv.fpApiVer < 6.1 and self.oTstDrv.fpApiVer >= 5.0) or not oTestVm.isWindows():
2676 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=', '===', vbox.ComError.E_INVALIDARG),
2677 tdStepSessionCheckEnv(),
2678 tdStepSessionSetEnv('=FOO', 'BAR', vbox.ComError.E_INVALIDARG),
2679 tdStepSessionCheckEnv(),
2680 tdStepSessionBulkEnv(['=', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2681 tdStepSessionCheckEnv(),
2682 tdStepSessionBulkEnv(['=FOO', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2683 tdStepSessionCheckEnv(),
2684 tdStepSessionBulkEnv(['=D:=D:/tmp', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2685 tdStepSessionCheckEnv(),
2686 tdStepSessionSetEnv('=D:', 'D:/temp', vbox.ComError.E_INVALIDARG),
2687 tdStepSessionCheckEnv(),
2688 ]));
2689 elif self.oTstDrv.fpApiVer >= 6.1 and oTestVm.isWindows():
2690 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=D:', 'D:/tmp'),
2691 tdStepSessionCheckEnv(['=D:=D:/tmp',]),
2692 tdStepSessionBulkEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2693 tdStepSessionCheckEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2694 tdStepSessionUnsetEnv('=D:'),
2695 tdStepSessionCheckEnv(['=D:', '=FOO', 'foo=bar']),
2696 ]));
2697
2698 return tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession, oTestVm, 'SessionEnv');
2699
2700 def testGuestCtrlSessionSimple(self, oSession, oTxsSession, oTestVm):
2701 """
2702 Tests simple session-based API calls.
2703 """
2704
2705 reporter.log('Testing simple session-based API calls ...');
2706
2707 # Start a valid session.
2708 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2709 try:
2710 oCreds = tdCtxCreds();
2711 oCreds.applyDefaultsIfNotSet(oTestVm);
2712 oGuest = oSession.o.console.guest;
2713 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionSimple");
2714 oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2715 except:
2716 reporter.logXcpt('Starting session for session-based API calls failed');
2717 return False;
2718
2719 fRc = True;
2720
2721 # Note: Starting with r161502 this should be fixed.
2722 # Session 0 separation started with Windows Vista, so skip everything older.
2723 if self.oTstDrv.uRevision >= 161502 \
2724 and oTestVm.isWindows() \
2725 and oTestVm.sKind not in ('WindowsNT3x', 'WindowsNT4', 'Windows2000', 'WindowsXP'):
2726 reporter.testStart('Windows guest processes in session >= 1');
2727 # Test in which Windows session Guest Control processes are being started.
2728 # We don't want them to be started in session 0, as this would prevent desktop interaction and other stuff.
2729 fRc, eExitStatus, iExitCode, _, _, _ = \
2730 self.executeGstCtlHelper(oTxsSession, oGuestSession, [ "show", "win-session-id" ]);
2731 if fRc \
2732 and eExitStatus == vboxcon.ProcessStatus_TerminatedNormally:
2733 if iExitCode >= 1000: # We report 1000 + <session ID> as exit code.
2734 uSessionId = iExitCode - 1000;
2735 if uSessionId >= 1:
2736 reporter.log('Guest processes start in session %d, good' % (uSessionId));
2737 else:
2738 reporter.error('Guest processes start in session 0, expected session >= 1');
2739 else:
2740 reporter.error('Guest Control Helper returned error %d (exit code)' % (iExitCode));
2741 reporter.testDone();
2742
2743 # User home.
2744 if self.oTstDrv.fpApiVer >= 7.0:
2745 reporter.log('Getting user\'s home directory ...');
2746 try:
2747 reporter.log('User home directory: %s' % (oGuestSession.userHome));
2748 except:
2749 fRc = reporter.logXcpt('Getting user home directory failed');
2750
2751 # User documents.
2752 if self.oTstDrv.fpApiVer >= 7.0:
2753 reporter.log('Getting user\'s documents directory ...');
2754 try:
2755 reporter.log('User documents directory: %s' % (oGuestSession.userDocuments));
2756 except:
2757 fRc = reporter.logXcpt('Getting user documents directory failed');
2758
2759 # Mount points. Only available for Guest Additions >= 7.1.
2760 if self.oTstDrv.fpApiVer >= 7.1:
2761 reporter.log('Getting mount points ...');
2762 try:
2763 aMountpoints = oGuestSession.getMountPoints();
2764 reporter.log('Got %ld mount points' % len(aMountpoints))
2765 for mountPoint in aMountpoints:
2766 reporter.log('Mountpoint: %s' % (mountPoint));
2767 except:
2768 fRc = reporter.logXcpt('Getting mount points failed');
2769
2770 # Close the session.
2771 try:
2772 oGuestSession.close();
2773 except:
2774 fRc = reporter.errorXcpt('Closing guest session failed');
2775
2776 return fRc;
2777
2778 def testGuestCtrlSession(self, oSession, oTxsSession, oTestVm):
2779 """
2780 Tests the guest session handling.
2781 """
2782
2783 #
2784 # Tests:
2785 #
2786 atTests = [
2787 # Invalid parameters.
2788 [ tdTestSession(sUser = ''), tdTestResultSession() ],
2789 # User account without a passwort - forbidden.
2790 [ tdTestSession(sPassword = "" ), tdTestResultSession() ],
2791 # Various wrong credentials.
2792 # Note! Only windows cares about sDomain, the other guests ignores it.
2793 # Note! On Guest Additions < 4.3 this always succeeds because these don't
2794 # support creating dedicated sessions. Instead, guest process creation
2795 # then will fail. See note below.
2796 [ tdTestSession(sPassword = 'bar'), tdTestResultSession() ],
2797 [ tdTestSession(sUser = 'foo', sPassword = 'bar'), tdTestResultSession() ],
2798 [ tdTestSession(sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2799 [ tdTestSession(sUser = 'foo', sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2800 ];
2801 if oTestVm.isWindows(): # domain is ignored elsewhere.
2802 atTests.append([ tdTestSession(sDomain = 'boo'), tdTestResultSession() ]);
2803
2804 # Finally, correct credentials.
2805 atTests.append([ tdTestSession(), tdTestResultSession(fRc = True, cNumSessions = 1) ]);
2806
2807 #
2808 # Run the tests.
2809 #
2810 fRc = True;
2811 for (i, tTest) in enumerate(atTests):
2812 oCurTest = tTest[0] # type: tdTestSession
2813 oCurRes = tTest[1] # type: tdTestResult
2814
2815 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2816 if not fRc:
2817 break;
2818 reporter.log('Testing #%d, user="%s", sPassword="%s", sDomain="%s" ...'
2819 % (i, oCurTest.oCreds.sUser, oCurTest.oCreds.sPassword, oCurTest.oCreds.sDomain));
2820 sCurGuestSessionName = 'testGuestCtrlSession: Test #%d' % (i,);
2821 fRc2, oCurGuestSession = oCurTest.createSession(sCurGuestSessionName, fIsError = oCurRes.fRc);
2822
2823 # See note about < 4.3 Guest Additions above.
2824 uProtocolVersion = 2;
2825 if oCurGuestSession is not None:
2826 try:
2827 uProtocolVersion = oCurGuestSession.protocolVersion;
2828 except:
2829 fRc = reporter.errorXcpt('Test #%d' % (i,));
2830
2831 if uProtocolVersion >= 2 and fRc2 is not oCurRes.fRc:
2832 fRc = reporter.error('Test #%d failed: Session creation failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
2833
2834 if fRc2 and oCurGuestSession is None:
2835 fRc = reporter.error('Test #%d failed: no session object' % (i,));
2836 fRc2 = False;
2837
2838 if fRc2:
2839 if uProtocolVersion >= 2: # For Guest Additions < 4.3 getSessionCount() always will return 1.
2840 cCurSessions = oCurTest.getSessionCount(self.oTstDrv.oVBoxMgr);
2841 if cCurSessions != oCurRes.cNumSessions:
2842 fRc = reporter.error('Test #%d failed: Session count does not match: Got %d, expected %d'
2843 % (i, cCurSessions, oCurRes.cNumSessions));
2844 try:
2845 sObjName = oCurGuestSession.name;
2846 except:
2847 fRc = reporter.errorXcpt('Test #%d' % (i,));
2848 else:
2849 if sObjName != sCurGuestSessionName:
2850 fRc = reporter.error('Test #%d failed: Session name does not match: Got "%s", expected "%s"'
2851 % (i, sObjName, sCurGuestSessionName));
2852 fRc2 = oCurTest.closeSession();
2853 if fRc2 is False:
2854 fRc = reporter.error('Test #%d failed: Session could not be closed' % (i,));
2855
2856 if fRc is False:
2857 return (False, oTxsSession);
2858
2859 #
2860 # Multiple sessions.
2861 #
2862 cMaxGuestSessions = 31; # Maximum number of concurrent guest session allowed.
2863 # Actually, this is 32, but we don't test session 0.
2864 aoMultiSessions = {};
2865 reporter.log2('Opening multiple guest tsessions at once ...');
2866 for i in xrange(cMaxGuestSessions + 1):
2867 aoMultiSessions[i] = tdTestSession(sSessionName = 'MultiSession #%d' % (i,));
2868 fRc = aoMultiSessions[i].setEnvironment(oSession, oTxsSession, oTestVm);
2869 if not fRc:
2870 break;
2871
2872 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2873 reporter.log2('MultiSession test #%d count is %d' % (i, cCurSessions));
2874 if cCurSessions != i:
2875 return (reporter.error('MultiSession count is %d, expected %d' % (cCurSessions, i)), oTxsSession);
2876 fRc2, _ = aoMultiSessions[i].createSession('MultiSession #%d' % (i,), i < cMaxGuestSessions);
2877 if fRc2 is not True:
2878 if i < cMaxGuestSessions:
2879 return (reporter.error('MultiSession #%d test failed' % (i,)), oTxsSession);
2880 reporter.log('MultiSession #%d exceeded concurrent guest session count, good' % (i,));
2881 break;
2882
2883 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2884 if cCurSessions is not cMaxGuestSessions:
2885 return (reporter.error('Final session count %d, expected %d ' % (cCurSessions, cMaxGuestSessions,)), oTxsSession);
2886
2887 reporter.log2('Closing MultiSessions ...');
2888 for i in xrange(cMaxGuestSessions):
2889 # Close this session:
2890 oClosedGuestSession = aoMultiSessions[i].oGuestSession;
2891 fRc2 = aoMultiSessions[i].closeSession();
2892 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr)
2893 reporter.log2('MultiSession #%d count is %d' % (i, cCurSessions,));
2894 if fRc2 is False:
2895 fRc = reporter.error('Closing MultiSession #%d failed' % (i,));
2896 elif cCurSessions != cMaxGuestSessions - (i + 1):
2897 fRc = reporter.error('Expected %d session after closing #%d, got %d instead'
2898 % (cMaxGuestSessions - (i + 1), cCurSessions, i,));
2899 assert aoMultiSessions[i].oGuestSession is None or not fRc2;
2900 ## @todo any way to check that the session is closed other than the 'sessions' attribute?
2901
2902 # Try check that none of the remaining sessions got closed.
2903 try:
2904 aoGuestSessions = self.oTstDrv.oVBoxMgr.getArray(atTests[0][0].oGuest, 'sessions');
2905 except:
2906 return (reporter.errorXcpt('i=%d/%d' % (i, cMaxGuestSessions,)), oTxsSession);
2907 if oClosedGuestSession in aoGuestSessions:
2908 fRc = reporter.error('i=%d/%d: %s should not be in %s'
2909 % (i, cMaxGuestSessions, oClosedGuestSession, aoGuestSessions));
2910 if i + 1 < cMaxGuestSessions: # Not sure what xrange(2,2) does...
2911 for j in xrange(i + 1, cMaxGuestSessions):
2912 if aoMultiSessions[j].oGuestSession not in aoGuestSessions:
2913 fRc = reporter.error('i=%d/j=%d/%d: %s should be in %s'
2914 % (i, j, cMaxGuestSessions, aoMultiSessions[j].oGuestSession, aoGuestSessions));
2915 ## @todo any way to check that they work?
2916
2917 ## @todo Test session timeouts.
2918
2919 fRc2 = self.testGuestCtrlSessionSimple(oSession, oTxsSession, oTestVm);
2920 if fRc:
2921 fRc = fRc2;
2922
2923 return (fRc, oTxsSession);
2924
2925 def testGuestCtrlSessionFileRefs(self, oSession, oTxsSession, oTestVm):
2926 """
2927 Tests the guest session file reference handling.
2928 """
2929
2930 # Find a file to play around with:
2931 sFile = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2932
2933 # Use credential defaults.
2934 oCreds = tdCtxCreds();
2935 oCreds.applyDefaultsIfNotSet(oTestVm);
2936
2937 # Number of stale guest files to create.
2938 cStaleFiles = 10;
2939
2940 #
2941 # Start a session.
2942 #
2943 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2944 try:
2945 oGuest = oSession.o.console.guest;
2946 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionFileRefs");
2947 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2948 except:
2949 return (reporter.errorXcpt(), oTxsSession);
2950
2951 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2952 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2953 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2954 reporter.log('Session successfully started');
2955
2956 #
2957 # Open guest files and "forget" them (stale entries).
2958 # For them we don't have any references anymore intentionally.
2959 #
2960 reporter.log2('Opening stale files');
2961 fRc = True;
2962 for i in xrange(0, cStaleFiles):
2963 try:
2964 if self.oTstDrv.fpApiVer >= 5.0:
2965 oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly, vboxcon.FileOpenAction_OpenExisting, 0);
2966 else:
2967 oGuestSession.fileOpen(sFile, "r", "oe", 0);
2968 # Note: Use a timeout in the call above for not letting the stale processes
2969 # hanging around forever. This can happen if the installed Guest Additions
2970 # do not support terminating guest processes.
2971 except:
2972 fRc = reporter.errorXcpt('Opening stale file #%d failed:' % (i,));
2973 break;
2974
2975 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2976 except: fRc = reporter.errorXcpt();
2977 else:
2978 if cFiles != cStaleFiles:
2979 fRc = reporter.error('Got %d stale files, expected %d' % (cFiles, cStaleFiles));
2980
2981 if fRc is True:
2982 #
2983 # Open non-stale files and close them again.
2984 #
2985 reporter.log2('Opening non-stale files');
2986 aoFiles = [];
2987 for i in xrange(0, cStaleFiles):
2988 try:
2989 if self.oTstDrv.fpApiVer >= 5.0:
2990 oCurFile = oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly,
2991 vboxcon.FileOpenAction_OpenExisting, 0);
2992 else:
2993 oCurFile = oGuestSession.fileOpen(sFile, "r", "oe", 0);
2994 aoFiles.append(oCurFile);
2995 except:
2996 fRc = reporter.errorXcpt('Opening non-stale file #%d failed:' % (i,));
2997 break;
2998
2999 # Check the count.
3000 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3001 except: fRc = reporter.errorXcpt();
3002 else:
3003 if cFiles != cStaleFiles * 2:
3004 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles * 2));
3005
3006 # Close them.
3007 reporter.log2('Closing all non-stale files again ...');
3008 for i, oFile in enumerate(aoFiles):
3009 try:
3010 oFile.close();
3011 except:
3012 fRc = reporter.errorXcpt('Closing non-stale file #%d failed:' % (i,));
3013
3014 # Check the count again.
3015 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3016 except: fRc = reporter.errorXcpt();
3017 # Here we count the stale files (that is, files we don't have a reference
3018 # anymore for) and the opened and then closed non-stale files (that we still keep
3019 # a reference in aoFiles[] for).
3020 if cFiles != cStaleFiles:
3021 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles));
3022
3023 #
3024 # Check that all (referenced) non-stale files are now in the "closed" state.
3025 #
3026 reporter.log2('Checking statuses of all non-stale files ...');
3027 for i, oFile in enumerate(aoFiles):
3028 try:
3029 eFileStatus = aoFiles[i].status;
3030 except:
3031 fRc = reporter.errorXcpt('Checking status of file #%d failed:' % (i,));
3032 else:
3033 if eFileStatus != vboxcon.FileStatus_Closed:
3034 fRc = reporter.error('Non-stale file #%d has status %d, expected %d'
3035 % (i, eFileStatus, vboxcon.FileStatus_Closed));
3036
3037 if fRc is True:
3038 reporter.log2('All non-stale files closed');
3039
3040 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
3041 except: fRc = reporter.errorXcpt();
3042 else: reporter.log2('Final guest session file count: %d' % (cFiles,));
3043
3044 #
3045 # Now try to close the session and see what happens.
3046 # Note! Session closing is why we've been doing all the 'if fRc is True' stuff above rather than returning.
3047 #
3048 reporter.log2('Closing guest session ...');
3049 try:
3050 oGuestSession.close();
3051 except:
3052 fRc = reporter.errorXcpt('Testing for stale processes failed:');
3053
3054 return (fRc, oTxsSession);
3055
3056 #def testGuestCtrlSessionDirRefs(self, oSession, oTxsSession, oTestVm):
3057 # """
3058 # Tests the guest session directory reference handling.
3059 # """
3060
3061 # fRc = True;
3062 # return (fRc, oTxsSession);
3063
3064 def testGuestCtrlSessionProcRefs(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
3065 """
3066 Tests the guest session process reference handling.
3067 """
3068
3069 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3070 asArgs = [sShell,];
3071
3072 # Use credential defaults.
3073 oCreds = tdCtxCreds();
3074 oCreds.applyDefaultsIfNotSet(oTestVm);
3075
3076 # Number of guest processes per group to create.
3077 cProcsPerGroup = 10;
3078
3079 #
3080 # Start a session.
3081 #
3082 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3083 try:
3084 oGuest = oSession.o.console.guest;
3085 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionProcRefs");
3086 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3087 except:
3088 return (reporter.errorXcpt(), oTxsSession);
3089
3090 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3091 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3092 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3093 reporter.log('Session successfully started');
3094
3095 #
3096 # Fire off forever-running processes and "forget" them (stale entries).
3097 # For them we don't have any references anymore intentionally.
3098 #
3099 reporter.log('Starting stale processes...');
3100 fRc = True;
3101 for i in xrange(0, cProcsPerGroup):
3102 try:
3103 reporter.log2('Starting stale process #%d...' % (i));
3104 self.processCreateWrapper(oGuestSession, sShell, asArgs, "", # Working directory.
3105 [], # Environment changes.
3106 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], 30 * 1000);
3107 # Note: Not keeping a process reference from the created process above is intentional and part of the test!
3108
3109 # Note: Use a timeout in the call above for not letting the stale processes
3110 # hanging around forever. This can happen if the installed Guest Additions
3111 # do not support terminating guest processes.
3112 except:
3113 fRc = reporter.errorXcpt('Creating stale process #%d failed:' % (i,));
3114 break;
3115
3116 if fRc:
3117 reporter.log2('Starting stale processes successful');
3118 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3119 except: fRc = reporter.errorXcpt();
3120 else:
3121 reporter.log2('Proccess count is: %d' % (cProcs));
3122 if cProcs != cProcsPerGroup:
3123 fRc = reporter.error('Got %d stale processes, expected %d (stale)' % (cProcs, cProcsPerGroup));
3124
3125 if fRc:
3126 #
3127 # Fire off non-stale processes and wait for termination.
3128 #
3129 if oTestVm.isWindows() or oTestVm.isOS2():
3130 asArgs = [ sShell, '/C', 'dir', '/S', self.oTstDrv.getGuestSystemDir(oTestVm), ];
3131 else:
3132 asArgs = [ sShell, '-c', 'ls -la ' + self.oTstDrv.getGuestSystemDir(oTestVm), ];
3133 reporter.log('Starting non-stale processes...');
3134 aoProcs = [];
3135 for i in xrange(0, cProcsPerGroup):
3136 try:
3137 reporter.log2('Starting non-stale process #%d...' % (i));
3138 oCurProc = self.processCreateWrapper(oGuestSession, sShell, asArgs,
3139 "", # Working directory.
3140 [], [], 0); # Infinite timeout.
3141 aoProcs.append(oCurProc);
3142 except:
3143 fRc = reporter.errorXcpt('Creating non-stale process #%d failed:' % (i,));
3144 break;
3145
3146 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3147 except: fRc = reporter.errorXcpt();
3148 else:
3149 reporter.log2('Proccess count is: %d' % (cProcs));
3150
3151 reporter.log('Waiting for non-stale processes to terminate...');
3152 for i, oProcess in enumerate(aoProcs):
3153 try:
3154 reporter.log('Waiting for non-stale process #%d...' % (i));
3155 eWaitResult = oProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 30 * 1000);
3156 eProcessStatus = oProcess.status;
3157 except:
3158 fRc = reporter.errorXcpt('Waiting for non-stale process #%d failed:' % (i,));
3159 else:
3160 if eProcessStatus != vboxcon.ProcessStatus_TerminatedNormally:
3161 fRc = reporter.error('Waiting for non-stale processes #%d resulted in status %d, expected %d (wr=%d)'
3162 % (i, eProcessStatus, vboxcon.ProcessStatus_TerminatedNormally, eWaitResult));
3163 if fRc:
3164 reporter.log('All non-stale processes ended successfully');
3165
3166 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3167 except: fRc = reporter.errorXcpt();
3168 else:
3169 reporter.log2('Proccess count is: %d' % (cProcs));
3170
3171 # Here we count the stale processes (that is, processes we don't have a reference
3172 # anymore for) and the started + ended non-stale processes (that we still keep
3173 # a reference in aoProcesses[] for).
3174 cProcsExpected = cProcsPerGroup * 2;
3175 if cProcs != cProcsExpected:
3176 fRc = reporter.error('Got %d total processes, expected %d (stale vs. non-stale)' \
3177 % (cProcs, cProcsExpected));
3178 #
3179 # Fire off non-stale blocking processes which are terminated via terminate().
3180 #
3181 if oTestVm.isWindows() or oTestVm.isOS2():
3182 sCmd = sShell;
3183 asArgs = [ sCmd, '/C', 'pause'];
3184 else:
3185 sCmd = '/usr/bin/yes';
3186 asArgs = [ sCmd ];
3187 reporter.log('Starting blocking processes...');
3188 aoProcs = [];
3189 for i in xrange(0, cProcsPerGroup):
3190 try:
3191 reporter.log2('Starting blocking process #%d...' % (i));
3192 oCurProc = self.processCreateWrapper(oGuestSession, sCmd, asArgs,
3193 "", # Working directory.
3194 [], [], 30 * 1000);
3195
3196 # Note: Use a timeout in the call above for not letting the stale processes
3197 # hanging around forever. This can happen if the installed Guest Additions
3198 # do not support terminating guest processes.
3199 try:
3200 reporter.log('Waiting for blocking process #%d getting started...' % (i));
3201 eWaitResult = oCurProc.waitForArray([ vboxcon.ProcessWaitForFlag_Start, ], 30 * 1000);
3202 eProcessStatus = oCurProc.status;
3203 except:
3204 fRc = reporter.errorXcpt('Waiting for blocking process #%d failed:' % (i,));
3205 else:
3206 if eProcessStatus != vboxcon.ProcessStatus_Started:
3207 fRc = reporter.error('Waiting for blocking processes #%d resulted in status %d, expected %d (wr=%d)'
3208 % (i, eProcessStatus, vboxcon.ProcessStatus_Started, eWaitResult));
3209 aoProcs.append(oCurProc);
3210 except:
3211 fRc = reporter.errorXcpt('Creating blocking process #%d failed:' % (i,));
3212 break;
3213
3214 if fRc:
3215 reporter.log2('Starting blocking processes successful');
3216
3217 reporter.log2('Terminating blocking processes...');
3218 for i, oProcess in enumerate(aoProcs):
3219 try:
3220 reporter.log('Terminating blocking process #%d...' % (i));
3221 oProcess.terminate();
3222 except: # Termination might not be supported, just skip and log it.
3223 reporter.logXcpt('Termination of blocking process #%d failed, skipped:' % (i,));
3224 if self.oTstDrv.fpApiVer >= 6.1: # Termination is supported since 5.2 or so.
3225 fRc = False;
3226 if fRc:
3227 reporter.log('All blocking processes were terminated successfully');
3228
3229 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3230 except: fRc = reporter.errorXcpt();
3231 else:
3232 # There still should be 20 processes because we just terminated the 10 blocking ones above.
3233 cProcsExpected = cProcsPerGroup * 2;
3234 if cProcs != cProcsExpected:
3235 fRc = reporter.error('Got %d total processes, expected %d (final)' % (cProcs, cProcsExpected));
3236 reporter.log2('Final guest session processes count: %d' % (cProcs,));
3237
3238 if not fRc:
3239 aoProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3240 for i, oProc in enumerate(aoProcs):
3241 try:
3242 aoArgs = self.oTstDrv.oVBoxMgr.getArray(oProc, 'arguments');
3243 reporter.log('Process %d (\'%s\') still around, status is %d' \
3244 % (i, ' '.join([str(x) for x in aoArgs]), oProc.status));
3245 except:
3246 reporter.errorXcpt('Process lookup failed:');
3247 #
3248 # Now try to close the session and see what happens.
3249 #
3250 reporter.log('Closing guest session ...');
3251 try:
3252 oGuestSession.close();
3253 except:
3254 fRc = reporter.errorXcpt('Closing session for testing process references failed:');
3255
3256 return (fRc, oTxsSession);
3257
3258 def testGuestCtrlExec(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
3259 """
3260 Tests the basic execution feature.
3261 """
3262
3263 # Paths:
3264 sVBoxControl = None; # Only available on supported Windows guests.
3265 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3266 sShellOpt = '/C' if oTestVm.isWindows() or oTestVm.isOS2() else '-c';
3267 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3268 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
3269 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
3270 if oTestVm.isWindows() or oTestVm.isOS2():
3271 sImageOut = self.oTstDrv.getGuestSystemShell(oTestVm);
3272 if oTestVm.isWindows():
3273 sVBoxControl = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm), 'VBoxControl.exe');
3274 else:
3275 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3276 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/ls", fIgnoreErrors = True):
3277 sImageOut = "/bin/ls";
3278 else:
3279 sImageOut = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'ls');
3280 if oTestVm.isLinux(): ## @todo check solaris and darwin.
3281 sVBoxControl = "/usr/bin/VBoxControl"; # Symlink
3282
3283 # Use credential defaults.
3284 oCreds = tdCtxCreds();
3285 oCreds.applyDefaultsIfNotSet(oTestVm);
3286
3287 atInvalid = [
3288 # Invalid parameters.
3289 [ tdTestExec(), tdTestResultExec() ],
3290 # Non-existent / invalid image.
3291 [ tdTestExec(sCmd = "non-existent"), tdTestResultExec() ],
3292 [ tdTestExec(sCmd = "non-existent2"), tdTestResultExec() ],
3293 # Use an invalid format string.
3294 [ tdTestExec(sCmd = "%$%%%&"), tdTestResultExec() ],
3295 # More stuff.
3296 [ tdTestExec(sCmd = u"ƒ‰‹ˆ÷‹¸"), tdTestResultExec() ],
3297 [ tdTestExec(sCmd = "???://!!!"), tdTestResultExec() ],
3298 [ tdTestExec(sCmd = "<>!\\"), tdTestResultExec() ],
3299 # Enable as soon as ERROR_BAD_DEVICE is implemented.
3300 #[ tdTestExec(sCmd = "CON", tdTestResultExec() ],
3301 ];
3302
3303 atExec = [];
3304 if oTestVm.isWindows() or oTestVm.isOS2():
3305 if oTestVm.sKind == 'WindowsNT4':
3306 # For whatever reason NT4 SP6 (tst-nt4sp6) returns exit code 2 for existing *and* non-existing files.
3307 # I've manually checked that on the VM itself, so this is *not* a bug in the Guest Control code.
3308 # So we have to tweak the expected exit codes here in order to make the following tests pass.
3309 iExitCodeForExistingFiles = 2
3310 iExitCodeForNonExistingFiles = 2
3311 else:
3312 iExitCodeForExistingFiles = 0
3313 iExitCodeForNonExistingFiles = 1
3314 atExec += [
3315 # Basic execution.
3316 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3317 tdTestResultExec(fRc = True) ],
3318 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sFileForReading ]),
3319 tdTestResultExec(fRc = True, iExitCode = iExitCodeForExistingFiles) ],
3320 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir + '\\nonexist.dll' ]),
3321 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3322 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ]),
3323 tdTestResultExec(fRc = True, iExitCode = 1) ],
3324 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3325 tdTestResultExec(fRc = True, iExitCode = 1) ],
3326 # StdOut.
3327 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3328 tdTestResultExec(fRc = True) ],
3329 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ]),
3330 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3331 # StdErr.
3332 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3333 tdTestResultExec(fRc = True) ],
3334 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ]),
3335 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3336 # StdOut + StdErr.
3337 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3338 tdTestResultExec(fRc = True) ],
3339 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ]),
3340 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3341 ];
3342
3343 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3344 atExec.extend([
3345 # Current working directory set (VBox >= 7.1).
3346 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3347 tdTestResultExec(fRc = True) ]
3348 ]);
3349
3350 # atExec.extend([
3351 # FIXME: Failing tests.
3352 # Environment variables.
3353 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3354 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3355 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3356 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3357 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3358 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3359 # aEnv = [ 'TEST_FOO=BAR' ],
3360 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3361 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3362 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3363 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3364 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3365 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3366
3367 ## @todo Create some files (or get files) we know the output size of to validate output length!
3368 ## @todo Add task which gets killed at some random time while letting the guest output something.
3369 #];
3370 else:
3371 atExec += [
3372 # Basic execution.
3373 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '-R', sSystemDir ]),
3374 tdTestResultExec(fRc = True) ],
3375 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sFileForReading ]),
3376 tdTestResultExec(fRc = True) ],
3377 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '--wrong-parameter' ]),
3378 tdTestResultExec(fRc = True, iExitCode = 2) ],
3379 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/non/existent' ]),
3380 tdTestResultExec(fRc = True, iExitCode = 2) ],
3381 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3382 tdTestResultExec(fRc = True, iExitCode = 127) ],
3383 # StdOut.
3384 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3385 tdTestResultExec(fRc = True) ],
3386 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdout-non-existing' ]),
3387 tdTestResultExec(fRc = True, iExitCode = 2) ],
3388 # StdErr.
3389 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3390 tdTestResultExec(fRc = True) ],
3391 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stderr-non-existing' ]),
3392 tdTestResultExec(fRc = True, iExitCode = 2) ],
3393 # StdOut + StdErr.
3394 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3395 tdTestResultExec(fRc = True) ],
3396 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdouterr-non-existing' ]),
3397 tdTestResultExec(fRc = True, iExitCode = 2) ],
3398 ];
3399
3400 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3401 atExec.extend([
3402 # Current working directory set (VBox >= 7.1).
3403 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '-R', sSystemDir ]),
3404 tdTestResultExec(fRc = True) ]
3405 ]);
3406
3407 # atExec.extend([
3408 # FIXME: Failing tests.
3409 # Environment variables.
3410 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3411 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3412 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3413 #
3414 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3415 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3416 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3417 # aEnv = [ 'TEST_FOO=BAR' ],
3418 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3419 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3420 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3421 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3422 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3423 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3424
3425 ## @todo Create some files (or get files) we know the output size of to validate output length!
3426 ## @todo Add task which gets killed at some random time while letting the guest output something.
3427 #];
3428
3429 #
3430 #for iExitCode in xrange(0, 127):
3431 # atExec.append([ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'exit %s' % iExitCode ]),
3432 # tdTestResultExec(fRc = True, iExitCode = iExitCode) ]);
3433
3434 if sVBoxControl \
3435 and self.oTstDrv.fpApiVer >= 6.0: # Investigate with this doesn't work on (<) 5.2.
3436 # Paths with spaces on windows.
3437 atExec.append([ tdTestExec(sCmd = sVBoxControl, asArgs = [ sVBoxControl, 'version' ],
3438 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3439 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3440 tdTestResultExec(fRc = True) ]);
3441
3442 # Test very long arguments. Be careful when tweaking this to not break the tests.
3443 # Regarding paths:
3444 # - We have RTPATH_BIG_MAX (64K)
3445 # - MSDN says 32K for CreateFileW()
3446 # - On Windows, each path component must not be longer than MAX_PATH (260), see
3447 # https://docs.microsoft.com/en-us/windows/win32/fileio/filesystem-functionality-comparison#limits
3448 #
3449 # Old(er) Windows OSes tend to crash in cmd.exe, so skip this on these OSes.
3450 if self.oTstDrv.fpApiVer >= 6.1 \
3451 and oTestVm.sKind not in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
3452 sEndMarker = '--end-marker';
3453 if oTestVm.isWindows() \
3454 or oTestVm.isOS2():
3455 sCmd = sShell;
3456 else:
3457 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3458 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/echo", fIgnoreErrors = True):
3459 sCmd = "/bin/echo";
3460 else:
3461 sCmd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'echo');
3462
3463 for _ in xrange(0, 16):
3464 if oTestVm.isWindows() \
3465 or oTestVm.isOS2():
3466 asArgs = [ sShell, sShellOpt, "echo" ];
3467 else:
3468 asArgs = [ sCmd ];
3469
3470 # Append a random number of arguments with random length.
3471 for _ in xrange(0, self.oTestFiles.oRandom.randrange(1, 64)):
3472 asArgs.append(''.join(random.choice(string.ascii_lowercase)
3473 for _ in range(self.oTestFiles.oRandom.randrange(1, 196))));
3474
3475 asArgs.append(sEndMarker);
3476
3477 reporter.log2('asArgs=%s (%d args), type=%s' % (limitString(asArgs), len(asArgs), type(asArgs)));
3478
3479 ## @todo Check limits; on Ubuntu with 256KB IPRT returns VERR_NOT_IMPLEMENTED.
3480 # Use a higher timeout (15 min) than usual for these long checks.
3481 atExec.append([ tdTestExec(sCmd = sCmd, asArgs = asArgs,
3482 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3483 vboxcon.ProcessCreateFlag_WaitForStdErr ],
3484 timeoutMS = 15 * 60 * 1000),
3485 tdTestResultExec(fRc = True) ]);
3486
3487 # Build up the final test array for the first batch.
3488 atTests = atInvalid + atExec;
3489
3490 #
3491 # First batch: One session per guest process.
3492 #
3493 reporter.log('One session per guest process ...');
3494 fRc = True;
3495 for (i, tTest) in enumerate(atTests):
3496 oCurTest = tTest[0] # type: tdTestExec
3497 oCurRes = tTest[1] # type: tdTestResultExec
3498 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3499 if not fRc:
3500 break;
3501 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlExec: Test #%d' % (i,));
3502 if fRc2 is not True:
3503 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3504 break;
3505 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession) and fRc;
3506 fRc = oCurTest.closeSession() and fRc;
3507
3508 reporter.log('Execution of all tests done, checking for stale sessions');
3509
3510 # No sessions left?
3511 try:
3512 aSessions = self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions');
3513 except:
3514 fRc = reporter.errorXcpt();
3515 else:
3516 cSessions = len(aSessions);
3517 if cSessions != 0:
3518 fRc = reporter.error('Found %d stale session(s), expected 0:' % (cSessions,));
3519 for (i, aSession) in enumerate(aSessions):
3520 try: reporter.log(' Stale session #%d ("%s")' % (aSession.id, aSession.name));
3521 except: reporter.errorXcpt();
3522
3523 if fRc is not True:
3524 return (fRc, oTxsSession);
3525
3526 reporter.log('Now using one guest session for all tests ...');
3527
3528 #
3529 # Second batch: One session for *all* guest processes.
3530 #
3531
3532 # Create session.
3533 reporter.log('Creating session for all tests ...');
3534 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
3535 try:
3536 oGuest = oSession.o.console.guest;
3537 oCurGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain,
3538 'testGuestCtrlExec: One session for all tests');
3539 except:
3540 return (reporter.errorXcpt(), oTxsSession);
3541
3542 try:
3543 eWaitResult = oCurGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3544 except:
3545 fRc = reporter.errorXcpt('Waiting for guest session to start failed:');
3546 else:
3547 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3548 fRc = reporter.error('Session did not start successfully, returned wait result: %d' % (eWaitResult,));
3549 else:
3550 reporter.log('Session successfully started');
3551
3552 # Do the tests within this session.
3553 for (i, tTest) in enumerate(atTests):
3554 oCurTest = tTest[0] # type: tdTestExec
3555 oCurRes = tTest[1] # type: tdTestResultExec
3556
3557 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3558 if not fRc:
3559 break;
3560 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession);
3561 if fRc is False:
3562 break;
3563
3564 # Close the session.
3565 reporter.log2('Closing guest session ...');
3566 try:
3567 oCurGuestSession.close();
3568 oCurGuestSession = None;
3569 except:
3570 fRc = reporter.errorXcpt('Closing guest session failed:');
3571
3572 # No sessions left?
3573 reporter.log('Execution of all tests done, checking for stale sessions again');
3574 try: cSessions = len(self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions'));
3575 except: fRc = reporter.errorXcpt();
3576 else:
3577 if cSessions != 0:
3578 fRc = reporter.error('Found %d stale session(s), expected 0' % (cSessions,));
3579 return (fRc, oTxsSession);
3580
3581 def threadForTestGuestCtrlSessionReboot(self, oGuestProcess):
3582 """
3583 Thread routine which waits for the stale guest process getting terminated (or some error)
3584 while the main test routine reboots the guest. It then compares the expected guest process result
3585 and logs an error if appropriate.
3586 """
3587 reporter.log('Waiting for process to get terminated at reboot ...');
3588 try:
3589 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate ], 5 * 60 * 1000);
3590 except:
3591 return reporter.errorXcpt('waitForArray failed');
3592 try:
3593 eStatus = oGuestProcess.status
3594 except:
3595 return reporter.errorXcpt('failed to get status (wait result %d)' % (eWaitResult,));
3596
3597 if eWaitResult == vboxcon.ProcessWaitResult_Terminate and eStatus == vboxcon.ProcessStatus_Down:
3598 reporter.log('Stale process was correctly terminated (status: down)');
3599 return True;
3600
3601 return reporter.error('Process wait across reboot failed: eWaitResult=%d, expected %d; eStatus=%d, expected %d'
3602 % (eWaitResult, vboxcon.ProcessWaitResult_Terminate, eStatus, vboxcon.ProcessStatus_Down,));
3603
3604 def testGuestCtrlSessionReboot(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3605 """
3606 Tests guest object notifications when a guest gets rebooted / shutdown.
3607
3608 These notifications gets sent from the guest sessions in order to make API clients
3609 aware of guest session changes.
3610
3611 To test that we create a stale guest process and trigger a reboot of the guest.
3612 """
3613
3614 ## @todo backport fixes to 6.0 and maybe 5.2
3615 if self.oTstDrv.fpApiVer <= 6.0:
3616 reporter.log('Skipping: Required fixes not yet backported!');
3617 return None;
3618
3619 # Use credential defaults.
3620 oCreds = tdCtxCreds();
3621 oCreds.applyDefaultsIfNotSet(oTestVm);
3622
3623 fRebooted = False;
3624 fRc = True;
3625
3626 #
3627 # Start a session.
3628 #
3629 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3630 try:
3631 oGuest = oSession.o.console.guest;
3632 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionReboot");
3633 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3634 except:
3635 return (reporter.errorXcpt(), oTxsSession);
3636
3637 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3638 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3639 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3640 reporter.log('Session successfully started');
3641
3642 #
3643 # Create a process.
3644 #
3645 # That process will also be used later to see if the session cleanup worked upon reboot.
3646 #
3647 sImage = self.oTstDrv.getGuestSystemShell(oTestVm);
3648 asArgs = [ sImage, ];
3649 aEnv = [];
3650 afFlags = [];
3651 try:
3652 oGuestProcess = self.processCreateWrapper(oGuestSession, sImage, asArgs,
3653 "", # Working directory.
3654 aEnv, afFlags, 30 * 1000);
3655 except:
3656 fRc = reporter.error('Failed to start shell process (%s)' % (sImage,));
3657 else:
3658 try:
3659 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3660 except:
3661 fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3662 else:
3663 # Check the result and state:
3664 try: eStatus = oGuestProcess.status;
3665 except: fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3666 else:
3667 reporter.log2('Starting process wait result returned: %d; Process status is: %d' % (eWaitResult, eStatus,));
3668 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3669 fRc = reporter.error('wait for ProcessWaitForFlag_Start failed: %d, expected %d (Start)'
3670 % (eWaitResult, vboxcon.ProcessWaitResult_Start,));
3671 elif eStatus != vboxcon.ProcessStatus_Started:
3672 fRc = reporter.error('Unexpected process status after startup: %d, wanted %d (Started)'
3673 % (eStatus, vboxcon.ProcessStatus_Started,));
3674 else:
3675 # Create a thread that waits on the process to terminate
3676 reporter.log('Creating reboot thread ...');
3677 oThreadReboot = threading.Thread(target = self.threadForTestGuestCtrlSessionReboot,
3678 args = (oGuestProcess,),
3679 name = 'threadForTestGuestCtrlSessionReboot');
3680 oThreadReboot.setDaemon(True); # pylint: disable=deprecated-method
3681 oThreadReboot.start();
3682
3683 # Do the reboot.
3684 reporter.log('Rebooting guest and reconnecting TXS ...');
3685 (oSession, oTxsSession) = self.oTstDrv.txsRebootAndReconnectViaTcp(oSession, oTxsSession,
3686 cMsTimeout = 3 * 60000);
3687 if oSession \
3688 and oTxsSession:
3689 # Set reboot flag (needed later for session closing).
3690 fRebooted = True;
3691 else:
3692 reporter.error('Rebooting via TXS failed');
3693 try: oGuestProcess.terminate();
3694 except: reporter.logXcpt();
3695 fRc = False;
3696
3697 reporter.log('Waiting for thread to finish ...');
3698 oThreadReboot.join();
3699
3700 # Check that the guest session now still has the formerly guest process object created above,
3701 # but with the "down" status now (because of guest reboot).
3702 try:
3703 aoGuestProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3704 if len(aoGuestProcs) == 1:
3705 enmProcSts = aoGuestProcs[0].status;
3706 if enmProcSts != vboxcon.ProcessStatus_Down:
3707 fRc = reporter.error('Old guest process (before reboot) has status %d, expected %s' \
3708 % (enmProcSts, vboxcon.ProcessStatus_Down));
3709 else:
3710 fRc = reporter.error('Old guest session (before reboot) has %d processes registered, expected 1' \
3711 % (len(aoGuestProcs)));
3712 except:
3713 fRc = reporter.errorXcpt();
3714 #
3715 # Try make sure we don't leave with a stale process on failure.
3716 #
3717 try: oGuestProcess.terminate();
3718 except: reporter.logXcpt();
3719
3720 #
3721 # Close the session.
3722 #
3723 reporter.log2('Closing guest session ...');
3724 try:
3725 oGuestSession.close();
3726 except:
3727 # Closing the guest session will fail when the guest reboot has been triggered,
3728 # as the session object will be cleared on a guest reboot.
3729 if fRebooted:
3730 reporter.logXcpt('Closing guest session failed, good (guest rebooted)');
3731 else: # ... otherwise this (still) should succeed. Report so if it doesn't.
3732 reporter.errorXcpt('Closing guest session failed');
3733
3734 return (fRc, oTxsSession);
3735
3736 def testGuestCtrlExecTimeout(self, oSession, oTxsSession, oTestVm):
3737 """
3738 Tests handling of timeouts of started guest processes.
3739 """
3740
3741 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3742
3743 # Use credential defaults.
3744 oCreds = tdCtxCreds();
3745 oCreds.applyDefaultsIfNotSet(oTestVm);
3746
3747 #
3748 # Create a session.
3749 #
3750 try:
3751 oGuest = oSession.o.console.guest;
3752 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlExecTimeout");
3753 eWaitResult = oGuestSession.waitForArray([ vboxcon.GuestSessionWaitForFlag_Start, ], 30 * 1000);
3754 except:
3755 return (reporter.errorXcpt(), oTxsSession);
3756
3757 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3758 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3759 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3760 reporter.log('Session successfully started');
3761
3762 #
3763 # Create a process which never terminates and should timeout when
3764 # waiting for termination.
3765 #
3766 fRc = True;
3767 try:
3768 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [ sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3769 "", # Working directory.
3770 [], [], 30 * 1000);
3771 except:
3772 fRc = reporter.errorXcpt();
3773 else:
3774 reporter.log('Waiting for process 1 being started ...');
3775 try:
3776 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3777 except:
3778 fRc = reporter.errorXcpt();
3779 else:
3780 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3781 fRc = reporter.error('Waiting for process 1 to start failed, got status %d' % (eWaitResult,));
3782 else:
3783 for msWait in (1, 32, 2000,):
3784 reporter.log('Waiting for process 1 to time out within %sms ...' % (msWait,));
3785 try:
3786 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], msWait);
3787 except:
3788 fRc = reporter.errorXcpt();
3789 break;
3790 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3791 fRc = reporter.error('Waiting for process 1 did not time out in %sms as expected: %d'
3792 % (msWait, eWaitResult,));
3793 break;
3794 reporter.log('Waiting for process 1 timed out in %u ms, good' % (msWait,));
3795
3796 try:
3797 oCurProcess.terminate();
3798 except:
3799 reporter.errorXcpt();
3800 oCurProcess = None;
3801
3802 #
3803 # Create another process that doesn't terminate, but which will be killed by VBoxService
3804 # because it ran out of execution time (3 seconds).
3805 #
3806 try:
3807 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3808 "", # Working directory.
3809 [], [], 3 * 1000);
3810 except:
3811 fRc = reporter.errorXcpt();
3812 else:
3813 reporter.log('Waiting for process 2 being started ...');
3814 try:
3815 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3816 except:
3817 fRc = reporter.errorXcpt();
3818 else:
3819 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3820 fRc = reporter.error('Waiting for process 2 to start failed, got status %d' % (eWaitResult,));
3821 else:
3822 reporter.log('Waiting for process 2 to get killed for running out of execution time ...');
3823 try:
3824 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 15 * 1000);
3825 except:
3826 fRc = reporter.errorXcpt();
3827 else:
3828 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3829 fRc = reporter.error('Waiting for process 2 did not time out when it should, got wait result %d'
3830 % (eWaitResult,));
3831 else:
3832 reporter.log('Waiting for process 2 did not time out, good: %s' % (eWaitResult,));
3833 try:
3834 eStatus = oCurProcess.status;
3835 except:
3836 fRc = reporter.errorXcpt();
3837 else:
3838 if eStatus != vboxcon.ProcessStatus_TimedOutKilled:
3839 fRc = reporter.error('Status of process 2 wrong; excepted %d, got %d'
3840 % (vboxcon.ProcessStatus_TimedOutKilled, eStatus));
3841 else:
3842 reporter.log('Status of process 2 is TimedOutKilled (%d) is it should be.'
3843 % (vboxcon.ProcessStatus_TimedOutKilled,));
3844 try:
3845 oCurProcess.terminate();
3846 except:
3847 reporter.logXcpt();
3848 oCurProcess = None;
3849
3850 #
3851 # Clean up the session.
3852 #
3853 try:
3854 oGuestSession.close();
3855 except:
3856 fRc = reporter.errorXcpt();
3857
3858 return (fRc, oTxsSession);
3859
3860 def testGuestCtrlDirCreate(self, oSession, oTxsSession, oTestVm):
3861 """
3862 Tests creation of guest directories.
3863 """
3864
3865 sScratch = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'testGuestCtrlDirCreate');
3866
3867 atTests = [
3868 # Invalid stuff.
3869 [ tdTestDirCreate(sDirectory = '' ), tdTestResultFailure() ],
3870 # More unusual stuff.
3871 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '.') ), tdTestResultFailure() ],
3872 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '..') ), tdTestResultFailure() ],
3873 [ tdTestDirCreate(sDirectory = '..' ), tdTestResultFailure() ],
3874 [ tdTestDirCreate(sDirectory = '../' ), tdTestResultFailure() ],
3875 [ tdTestDirCreate(sDirectory = '../../' ), tdTestResultFailure() ],
3876 [ tdTestDirCreate(sDirectory = '/' ), tdTestResultFailure() ],
3877 [ tdTestDirCreate(sDirectory = '/..' ), tdTestResultFailure() ],
3878 [ tdTestDirCreate(sDirectory = '/../' ), tdTestResultFailure() ],
3879 ];
3880 if oTestVm.isWindows() or oTestVm.isOS2():
3881 atTests.extend([
3882 [ tdTestDirCreate(sDirectory = 'C:\\' ), tdTestResultFailure() ],
3883 [ tdTestDirCreate(sDirectory = 'C:\\..' ), tdTestResultFailure() ],
3884 [ tdTestDirCreate(sDirectory = 'C:\\..\\' ), tdTestResultFailure() ],
3885 [ tdTestDirCreate(sDirectory = 'C:/' ), tdTestResultFailure() ],
3886 [ tdTestDirCreate(sDirectory = 'C:/.' ), tdTestResultFailure() ],
3887 [ tdTestDirCreate(sDirectory = 'C:/./' ), tdTestResultFailure() ],
3888 [ tdTestDirCreate(sDirectory = 'C:/..' ), tdTestResultFailure() ],
3889 [ tdTestDirCreate(sDirectory = 'C:/../' ), tdTestResultFailure() ],
3890 [ tdTestDirCreate(sDirectory = '\\\\uncrulez\\foo' ), tdTestResultFailure() ],
3891 ]);
3892 atTests.extend([
3893 # Existing directories and files.
3894 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemDir(oTestVm) ), tdTestResultFailure() ],
3895 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemShell(oTestVm) ), tdTestResultFailure() ],
3896 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemFileForReading(oTestVm) ), tdTestResultFailure() ],
3897 # Creating directories.
3898 [ tdTestDirCreate(sDirectory = sScratch ), tdTestResultSuccess() ],
3899 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3900 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3901 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3902 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3903 # Try format strings as directories.
3904 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo%sbar%sbaz%d' )), tdTestResultSuccess() ],
3905 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, '%f%%boo%%bar%RI32' )), tdTestResultSuccess() ],
3906 # Long random names.
3907 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(36, 28))),
3908 tdTestResultSuccess() ],
3909 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(140, 116))),
3910 tdTestResultSuccess() ],
3911 # Too long names. ASSUMES a guests has a 255 filename length limitation.
3912 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3913 tdTestResultFailure() ],
3914 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3915 tdTestResultFailure() ],
3916 # Missing directory in path.
3917 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo1', 'bar') ), tdTestResultFailure() ],
3918 ]);
3919
3920 fRc = True;
3921 for (i, tTest) in enumerate(atTests):
3922 oCurTest = tTest[0] # type: tdTestDirCreate
3923 oCurRes = tTest[1] # type: tdTestResult
3924 reporter.log('Testing #%d, sDirectory="%s" ...' % (i, limitString(oCurTest.sDirectory),));
3925
3926 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3927 if not fRc:
3928 break;
3929 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreate: Test #%d' % (i,));
3930 if fRc is False:
3931 return reporter.error('Test #%d failed: Could not create session' % (i,));
3932
3933 fRc = self.gctrlCreateDir(oCurTest, oCurRes, oCurGuestSession);
3934
3935 fRc = oCurTest.closeSession() and fRc;
3936 if fRc is False:
3937 fRc = reporter.error('Test #%d failed' % (i,));
3938
3939 return (fRc, oTxsSession);
3940
3941 def testGuestCtrlDirCreateTemp(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3942 """
3943 Tests creation of temporary directories.
3944 """
3945
3946 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3947 atTests = [
3948 # Invalid stuff (template must have one or more trailin 'X'es (upper case only), or a cluster of three or more).
3949 [ tdTestDirCreateTemp(sDirectory = ''), tdTestResultFailure() ],
3950 [ tdTestDirCreateTemp(sDirectory = sSystemDir, fMode = 1234), tdTestResultFailure() ],
3951 [ tdTestDirCreateTemp(sTemplate = 'xXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3952 [ tdTestDirCreateTemp(sTemplate = 'xxx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3953 [ tdTestDirCreateTemp(sTemplate = 'XXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3954 [ tdTestDirCreateTemp(sTemplate = 'bar', sDirectory = 'whatever', fMode = 0o700), tdTestResultFailure() ],
3955 [ tdTestDirCreateTemp(sTemplate = 'foo', sDirectory = 'it is not used', fMode = 0o700), tdTestResultFailure() ],
3956 [ tdTestDirCreateTemp(sTemplate = 'X,so', sDirectory = 'pointless test', fMode = 0o700), tdTestResultFailure() ],
3957 # Non-existing stuff.
3958 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX',
3959 sDirectory = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'non', 'existing')),
3960 tdTestResultFailure() ],
3961 # Working stuff:
3962 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3963 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3964 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3965 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3966 tdTestResultFailure() ],
3967 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3968 tdTestResultFailure() ],
3969 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3970 tdTestResultFailure() ],
3971 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3972 tdTestResultFailure() ],
3973 ];
3974
3975 if self.oTstDrv.fpApiVer >= 7.0:
3976 # Weird mode set.
3977 atTests.extend([
3978 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o42333),
3979 tdTestResultFailure() ]
3980 ]);
3981 # Same as working stuff above, but with a different mode set.
3982 atTests.extend([
3983 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3984 tdTestResultFailure() ],
3985 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3986 tdTestResultFailure() ],
3987 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3988 tdTestResultFailure() ],
3989 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3990 tdTestResultFailure() ],
3991 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3992 tdTestResultFailure() ],
3993 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3994 tdTestResultFailure() ],
3995 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3996 tdTestResultFailure() ]
3997 ]);
3998 # Same as working stuff above, but with secure mode set.
3999 atTests.extend([
4000 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4001 tdTestResultFailure() ],
4002 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4003 tdTestResultFailure() ],
4004 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4005 tdTestResultFailure() ],
4006 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
4007 tdTestResultFailure() ],
4008 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4009 fSecure = True),
4010 tdTestResultFailure() ],
4011 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4012 fSecure = True),
4013 tdTestResultFailure() ],
4014 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
4015 fSecure = True),
4016 tdTestResultFailure() ]
4017 ]);
4018
4019 fRc = True;
4020 for (i, tTest) in enumerate(atTests):
4021 oCurTest = tTest[0] # type: tdTestDirCreateTemp
4022 oCurRes = tTest[1] # type: tdTestResult
4023 reporter.log('Testing #%d, sTemplate="%s", fMode=%#o, path="%s", secure="%s" ...' %
4024 (i, oCurTest.sTemplate, oCurTest.fMode, oCurTest.sDirectory, oCurTest.fSecure));
4025
4026 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4027 if not fRc:
4028 break;
4029 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreateTemp: Test #%d' % (i,));
4030 if fRc is False:
4031 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4032 break;
4033
4034 sDirTemp = '';
4035 try:
4036 sDirTemp = oCurGuestSession.directoryCreateTemp(oCurTest.sTemplate, oCurTest.fMode,
4037 oCurTest.sDirectory, oCurTest.fSecure);
4038 except:
4039 if oCurRes.fRc is True:
4040 fRc = reporter.errorXcpt('Creating temp directory "%s" failed:' % (oCurTest.sDirectory,));
4041 else:
4042 reporter.logXcpt('Creating temp directory "%s" failed expectedly, skipping:' % (oCurTest.sDirectory,));
4043 else:
4044 reporter.log2('Temporary directory is: "%s"' % (limitString(sDirTemp),));
4045 if not sDirTemp:
4046 fRc = reporter.error('Resulting directory is empty!');
4047 else:
4048 ## @todo This does not work for some unknown reason.
4049 #try:
4050 # if self.oTstDrv.fpApiVer >= 5.0:
4051 # fExists = oCurGuestSession.directoryExists(sDirTemp, False);
4052 # else:
4053 # fExists = oCurGuestSession.directoryExists(sDirTemp);
4054 #except:
4055 # fRc = reporter.errorXcpt('sDirTemp=%s' % (sDirTemp,));
4056 #else:
4057 # if fExists is not True:
4058 # fRc = reporter.error('Test #%d failed: Temporary directory "%s" does not exists (%s)'
4059 # % (i, sDirTemp, fExists));
4060 try:
4061 oFsObjInfo = oCurGuestSession.fsObjQueryInfo(sDirTemp, False);
4062 eType = oFsObjInfo.type;
4063 except:
4064 fRc = reporter.errorXcpt('sDirTemp="%s"' % (sDirTemp,));
4065 else:
4066 reporter.log2('%s: eType=%s (dir=%d)' % (limitString(sDirTemp), eType, vboxcon.FsObjType_Directory,));
4067 if eType != vboxcon.FsObjType_Directory:
4068 fRc = reporter.error('Temporary directory "%s" not created as a directory: eType=%d'
4069 % (sDirTemp, eType));
4070 fRc = oCurTest.closeSession() and fRc;
4071 return (fRc, oTxsSession);
4072
4073 def testGuestCtrlDirRead(self, oSession, oTxsSession, oTestVm):
4074 """
4075 Tests opening and reading (enumerating) guest directories.
4076 """
4077
4078 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
4079 atTests = [
4080 # Invalid stuff.
4081 [ tdTestDirRead(sDirectory = ''), tdTestResultDirRead() ],
4082 [ tdTestDirRead(sDirectory = sSystemDir, afFlags = [ 1234 ]), tdTestResultDirRead() ],
4083 [ tdTestDirRead(sDirectory = sSystemDir, sFilter = '*.foo'), tdTestResultDirRead() ],
4084 # Non-existing stuff.
4085 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'really-no-such-subdir')), tdTestResultDirRead() ],
4086 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'non', 'existing')), tdTestResultDirRead() ],
4087 ];
4088
4089 if oTestVm.isWindows() or oTestVm.isOS2():
4090 atTests.extend([
4091 # More unusual stuff.
4092 [ tdTestDirRead(sDirectory = 'z:\\'), tdTestResultDirRead() ],
4093 [ tdTestDirRead(sDirectory = '\\\\uncrulez\\foo'), tdTestResultDirRead() ],
4094 ]);
4095
4096 # Read the system directory (ASSUMES at least 5 files in it):
4097 # Windows 7+ has inaccessible system32/com/dmp directory that screws up this test, so skip it on windows:
4098 if not oTestVm.isWindows():
4099 atTests.append([ tdTestDirRead(sDirectory = sSystemDir),
4100 tdTestResultDirRead(fRc = True, cFiles = -5, cDirs = None) ]);
4101 ## @todo trailing slash
4102
4103 # Read from the test file set.
4104 atTests.extend([
4105 [ tdTestDirRead(sDirectory = self.oTestFiles.oEmptyDir.sPath),
4106 tdTestResultDirRead(fRc = True, cFiles = 0, cDirs = 0, cOthers = 0) ],
4107 [ tdTestDirRead(sDirectory = self.oTestFiles.oManyDir.sPath),
4108 tdTestResultDirRead(fRc = True, cFiles = len(self.oTestFiles.oManyDir.aoChildren), cDirs = 0, cOthers = 0) ],
4109 [ tdTestDirRead(sDirectory = self.oTestFiles.oTreeDir.sPath),
4110 tdTestResultDirRead(fRc = True, cFiles = self.oTestFiles.cTreeFiles, cDirs = self.oTestFiles.cTreeDirs,
4111 cOthers = self.oTestFiles.cTreeOthers) ],
4112 ]);
4113
4114
4115 fRc = True;
4116 for (i, tTest) in enumerate(atTests):
4117 oCurTest = tTest[0] # type: tdTestExec
4118 oCurRes = tTest[1] # type: tdTestResultDirRead
4119
4120 reporter.log('Testing #%d, dir="%s" ...' % (i, oCurTest.sDirectory));
4121 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4122 if not fRc:
4123 break;
4124 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: Test #%d' % (i,));
4125 if fRc is not True:
4126 break;
4127 fUseDirList = False;
4128 cEntriesPerRead = random.randrange(1, 32768);
4129 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4130 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4131 # Listing directories only is available for >= VBox 7.1.
4132 fUseDirList = random.choice( [True, False] );
4133 (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc,
4134 fUseDirList, cEntriesPerRead);
4135 fRc = oCurTest.closeSession() and fRc;
4136
4137 reporter.log2('Test #%d: Returned %d directories, %d files total' % (i, cDirs, cFiles));
4138 if fRc2 is oCurRes.fRc:
4139 if fRc2 is True:
4140 if oCurRes.cFiles is None:
4141 pass; # ignore
4142 elif oCurRes.cFiles >= 0 and cFiles != oCurRes.cFiles:
4143 fRc = reporter.error('Test #%d failed: Got %d files, expected %d' % (i, cFiles, oCurRes.cFiles));
4144 elif oCurRes.cFiles < 0 and cFiles < -oCurRes.cFiles:
4145 fRc = reporter.error('Test #%d failed: Got %d files, expected at least %d'
4146 % (i, cFiles, -oCurRes.cFiles));
4147 if oCurRes.cDirs is None:
4148 pass; # ignore
4149 elif oCurRes.cDirs >= 0 and cDirs != oCurRes.cDirs:
4150 fRc = reporter.error('Test #%d failed: Got %d directories, expected %d' % (i, cDirs, oCurRes.cDirs));
4151 elif oCurRes.cDirs < 0 and cDirs < -oCurRes.cDirs:
4152 fRc = reporter.error('Test #%d failed: Got %d directories, expected at least %d'
4153 % (i, cDirs, -oCurRes.cDirs));
4154 if oCurRes.cOthers is None:
4155 pass; # ignore
4156 elif oCurRes.cOthers >= 0 and cOthers != oCurRes.cOthers:
4157 fRc = reporter.error('Test #%d failed: Got %d other types, expected %d' % (i, cOthers, oCurRes.cOthers));
4158 elif oCurRes.cOthers < 0 and cOthers < -oCurRes.cOthers:
4159 fRc = reporter.error('Test #%d failed: Got %d other types, expected at least %d'
4160 % (i, cOthers, -oCurRes.cOthers));
4161
4162 else:
4163 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4164
4165
4166 #
4167 # Go over a few directories in the test file set and compare names,
4168 # types and sizes rather than just the counts like we did above.
4169 #
4170 if fRc is True:
4171 oCurTest = tdTestDirRead();
4172 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4173 if fRc:
4174 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: gctrlReadDirTree2');
4175 if fRc is True:
4176 for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
4177 reporter.log('Checking "%s" ...' % (oDir.sPath,));
4178 fUseDirList = False;
4179 cEntriesPerRead = random.randrange(1, 32768);
4180 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4181 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4182 # Listing directories only is available for >= VBox 7.1.
4183 fUseDirList = random.choice( [True, False] );
4184 fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir, fUseDirList, cEntriesPerRead) and fRc;
4185 fRc = oCurTest.closeSession() and fRc;
4186
4187 return (fRc, oTxsSession);
4188
4189
4190 def testGuestCtrlFileRemove(self, oSession, oTxsSession, oTestVm):
4191 """
4192 Tests removing guest files.
4193 """
4194
4195 #
4196 # Create a directory with a few files in it using TXS that we'll use for the initial tests.
4197 #
4198 asTestDirs = [
4199 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1'), # [0]
4200 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1'), # [1]
4201 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1', 'subsubdir-1'), # [2]
4202 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2'), # [3]
4203 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2'), # [4]
4204 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2', 'subsbudir-2'), # [5]
4205 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-3'), # [6]
4206 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-4'), # [7]
4207 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5'), # [8]
4208 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5', 'subdir-5'), # [9]
4209 ]
4210 asTestFiles = [
4211 oTestVm.pathJoin(asTestDirs[0], 'file-0'), # [0]
4212 oTestVm.pathJoin(asTestDirs[0], 'file-1'), # [1]
4213 oTestVm.pathJoin(asTestDirs[0], 'file-2'), # [2]
4214 oTestVm.pathJoin(asTestDirs[1], 'file-3'), # [3] - subdir-1
4215 oTestVm.pathJoin(asTestDirs[1], 'file-4'), # [4] - subdir-1
4216 oTestVm.pathJoin(asTestDirs[2], 'file-5'), # [5] - subsubdir-1
4217 oTestVm.pathJoin(asTestDirs[3], 'file-6'), # [6] - rmtestdir-2
4218 oTestVm.pathJoin(asTestDirs[4], 'file-7'), # [7] - subdir-2
4219 oTestVm.pathJoin(asTestDirs[5], 'file-8'), # [8] - subsubdir-2
4220 ];
4221 for sDir in asTestDirs:
4222 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
4223 return reporter.error('Failed to create test dir "%s"!' % (sDir,));
4224 for sFile in asTestFiles:
4225 if oTxsSession.syncUploadString(sFile, sFile, 0o666) is not True:
4226 return reporter.error('Failed to create test file "%s"!' % (sFile,));
4227
4228 #
4229 # Tear down the directories and files.
4230 #
4231 aoTests = [
4232 # Negative tests first:
4233 tdTestRemoveFile(asTestDirs[0], fRcExpect = False),
4234 tdTestRemoveDir(asTestDirs[0], fRcExpect = False),
4235 tdTestRemoveDir(asTestFiles[0], fRcExpect = False),
4236 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-file'), fRcExpect = False),
4237 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir'), fRcExpect = False),
4238 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-file'), fRcExpect = False),
4239 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-subdir'), fRcExpect = False),
4240 tdTestRemoveTree(asTestDirs[0], afFlags = [], fRcExpect = False), # Only removes empty dirs, this isn't empty.
4241 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fRcExpect = False), # ditto
4242 # Empty paths:
4243 tdTestRemoveFile('', fRcExpect = False),
4244 tdTestRemoveDir('', fRcExpect = False),
4245 tdTestRemoveTree('', fRcExpect = False),
4246 # Now actually remove stuff:
4247 tdTestRemoveDir(asTestDirs[7], fRcExpect = True),
4248 tdTestRemoveFile(asTestDirs[6], fRcExpect = False),
4249 tdTestRemoveDir(asTestDirs[6], fRcExpect = True),
4250 tdTestRemoveFile(asTestFiles[0], fRcExpect = True),
4251 tdTestRemoveFile(asTestFiles[0], fRcExpect = False),
4252 # 17:
4253 tdTestRemoveTree(asTestDirs[8], fRcExpect = True), # Removes empty subdirs and leaves the dir itself.
4254 tdTestRemoveDir(asTestDirs[8], fRcExpect = True),
4255 tdTestRemoveTree(asTestDirs[3], fRcExpect = False), # Have subdirs & files,
4256 tdTestRemoveTree(asTestDirs[3], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,], fRcExpect = True),
4257 tdTestRemoveDir(asTestDirs[3], fRcExpect = True),
4258 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4259 # No error if already delete (RTDirRemoveRecursive artifact).
4260 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4261 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,],
4262 fNotExist = True, fRcExpect = True),
4263 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fNotExist = True, fRcExpect = True),
4264 ];
4265
4266 #
4267 # Execution loop
4268 #
4269 fRc = True;
4270 for (i, oTest) in enumerate(aoTests): # int, tdTestRemoveBase
4271 reporter.log('Testing #%d, path="%s" %s ...' % (i, oTest.sPath, oTest.__class__.__name__));
4272 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4273 if not fRc:
4274 break;
4275 fRc, _ = oTest.createSession('testGuestCtrlFileRemove: Test #%d' % (i,));
4276 if fRc is False:
4277 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4278 break;
4279 fRc = oTest.execute(self) and fRc;
4280 fRc = oTest.closeSession() and fRc;
4281
4282 if fRc is True:
4283 oCurTest = tdTestDirRead();
4284 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4285 if fRc:
4286 fRc, oCurGuestSession = oCurTest.createSession('remove final');
4287 if fRc is True:
4288
4289 #
4290 # Delete all the files in the many subdir of the test set.
4291 #
4292 reporter.log('Deleting the file in "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
4293 for oFile in self.oTestFiles.oManyDir.aoChildren:
4294 reporter.log2('"%s"' % (limitString(oFile.sPath),));
4295 try:
4296 if self.oTstDrv.fpApiVer >= 5.0:
4297 oCurGuestSession.fsObjRemove(oFile.sPath);
4298 else:
4299 oCurGuestSession.fileRemove(oFile.sPath);
4300 except:
4301 fRc = reporter.errorXcpt('Removing "%s" failed' % (oFile.sPath,));
4302
4303 # Remove the directory itself to verify that we've removed all the files in it:
4304 reporter.log('Removing the directory "%s" ...' % (self.oTestFiles.oManyDir.sPath,));
4305 try:
4306 oCurGuestSession.directoryRemove(self.oTestFiles.oManyDir.sPath);
4307 except:
4308 fRc = reporter.errorXcpt('Removing directory "%s" failed' % (self.oTestFiles.oManyDir.sPath,));
4309
4310 #
4311 # Recursively delete the entire test file tree from the root up.
4312 #
4313 # Note! On unix we cannot delete the root dir itself since it is residing
4314 # in /var/tmp where only the owner may delete it. Root is the owner.
4315 #
4316 if oTestVm.isWindows() or oTestVm.isOS2():
4317 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,];
4318 else:
4319 afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,];
4320 try:
4321 oProgress = oCurGuestSession.directoryRemoveRecursive(self.oTestFiles.oRoot.sPath, afFlags);
4322 except:
4323 fRc = reporter.errorXcpt('Removing tree "%s" failed' % (self.oTestFiles.oRoot.sPath,));
4324 else:
4325 oWrappedProgress = vboxwrappers.ProgressWrapper(oProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv,
4326 "remove-tree-root: %s" % (self.oTestFiles.oRoot.sPath,));
4327 reporter.log2('waiting ...')
4328 oWrappedProgress.wait();
4329 reporter.log2('isSuccess=%s' % (oWrappedProgress.isSuccess(),));
4330 if not oWrappedProgress.isSuccess():
4331 fRc = oWrappedProgress.logResult();
4332
4333 fRc = oCurTest.closeSession() and fRc;
4334
4335 return (fRc, oTxsSession);
4336
4337
4338 def testGuestCtrlFileStat(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4339 """
4340 Tests querying file information through stat.
4341 """
4342
4343 # Basic stuff, existing stuff.
4344 aoTests = [
4345 tdTestSessionEx([
4346 tdStepStatDir('.'),
4347 tdStepStatDir('..'),
4348 tdStepStatDir(self.oTstDrv.getGuestTempDir(oTestVm)),
4349 tdStepStatDir(self.oTstDrv.getGuestSystemDir(oTestVm)),
4350 tdStepStatDirEx(self.oTestFiles.oRoot),
4351 tdStepStatDirEx(self.oTestFiles.oEmptyDir),
4352 tdStepStatDirEx(self.oTestFiles.oTreeDir),
4353 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4354 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4355 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4356 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4357 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4358 tdStepStatDirEx(self.oTestFiles.chooseRandomDirFromTree()),
4359 tdStepStatFile(self.oTstDrv.getGuestSystemFileForReading(oTestVm)),
4360 tdStepStatFile(self.oTstDrv.getGuestSystemShell(oTestVm)),
4361 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4362 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4363 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4364 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4365 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4366 tdStepStatFileEx(self.oTestFiles.chooseRandomFile()),
4367 ]),
4368 ];
4369
4370 # None existing stuff.
4371 sSysDir = self.oTstDrv.getGuestSystemDir(oTestVm);
4372 sSep = oTestVm.pathSep();
4373 aoTests += [
4374 tdTestSessionEx([
4375 tdStepStatFileNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory')),
4376 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory') + sSep),
4377 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', '.')),
4378 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory')),
4379 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory') + sSep),
4380 tdStepStatPathNotFound(oTestVm.pathJoin(sSysDir, 'NoSuchFileOrDirectory', 'NoSuchFileOrSubDirectory', '.')),
4381 #tdStepStatPathNotFound('N:\\'), # ASSUMES nothing mounted on N:!
4382 #tdStepStatPathNotFound('\\\\NoSuchUncServerName\\NoSuchShare'),
4383 ]),
4384 ];
4385 # Invalid parameter check.
4386 aoTests += [ tdTestSessionEx([ tdStepStat('', vbox.ComError.E_INVALIDARG), ]), ];
4387
4388 #
4389 # Execute the tests.
4390 #
4391 fRc, oTxsSession = tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession,
4392 oTestVm, 'FsStat');
4393 #
4394 # Test the full test file set.
4395 #
4396 if self.oTstDrv.fpApiVer < 5.0:
4397 return (fRc, oTxsSession);
4398
4399 oTest = tdTestGuestCtrlBase();
4400 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4401 if not fRc:
4402 return (False, oTxsSession);
4403 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4404 if fRc2 is not True:
4405 return (False, oTxsSession);
4406
4407 for oFsObj in self.oTestFiles.dPaths.values():
4408 reporter.log2('testGuestCtrlFileStat: %s sPath=%s'
4409 % ('file' if isinstance(oFsObj, testfileset.TestFile) else 'dir ', limitString(oFsObj.sPath),));
4410
4411 # Query the information:
4412 try:
4413 oFsInfo = oGuestSession.fsObjQueryInfo(oFsObj.sPath, False);
4414 except:
4415 fRc = reporter.errorXcpt('sPath=%s type=%s: fsObjQueryInfo trouble!' % (oFsObj.sPath, type(oFsObj),));
4416 continue;
4417 if oFsInfo is None:
4418 fRc = reporter.error('sPath=%s type=%s: No info object returned!' % (oFsObj.sPath, type(oFsObj),));
4419 continue;
4420
4421 # Check attributes:
4422 try:
4423 eType = oFsInfo.type;
4424 cbObject = oFsInfo.objectSize;
4425 except:
4426 fRc = reporter.errorXcpt('sPath=%s type=%s: attribute access trouble!' % (oFsObj.sPath, type(oFsObj),));
4427 continue;
4428
4429 if isinstance(oFsObj, testfileset.TestFile):
4430 if eType != vboxcon.FsObjType_File:
4431 fRc = reporter.error('sPath=%s type=file: eType=%s, expected %s!'
4432 % (oFsObj.sPath, eType, vboxcon.FsObjType_File));
4433 if cbObject != oFsObj.cbContent:
4434 fRc = reporter.error('sPath=%s type=file: cbObject=%s, expected %s!'
4435 % (oFsObj.sPath, cbObject, oFsObj.cbContent));
4436 fFileExists = True;
4437 fDirExists = False;
4438 elif isinstance(oFsObj, testfileset.TestDir):
4439 if eType != vboxcon.FsObjType_Directory:
4440 fRc = reporter.error('sPath=%s type=dir: eType=%s, expected %s!'
4441 % (oFsObj.sPath, eType, vboxcon.FsObjType_Directory));
4442 fFileExists = False;
4443 fDirExists = True;
4444 else:
4445 fRc = reporter.error('sPath=%s type=%s: Unexpected oFsObj type!' % (oFsObj.sPath, type(oFsObj),));
4446 continue;
4447
4448 # Check the directoryExists and fileExists results too.
4449 try:
4450 fExistsResult = oGuestSession.fileExists(oFsObj.sPath, False);
4451 except:
4452 fRc = reporter.errorXcpt('sPath=%s type=%s: fileExists trouble!' % (oFsObj.sPath, type(oFsObj),));
4453 else:
4454 if fExistsResult != fFileExists:
4455 fRc = reporter.error('sPath=%s type=%s: fileExists returned %s, expected %s!'
4456 % (oFsObj.sPath, type(oFsObj), fExistsResult, fFileExists));
4457 try:
4458 fExistsResult = oGuestSession.directoryExists(oFsObj.sPath, False);
4459 except:
4460 fRc = reporter.errorXcpt('sPath=%s type=%s: directoryExists trouble!' % (oFsObj.sPath, type(oFsObj),));
4461 else:
4462 if fExistsResult != fDirExists:
4463 fRc = reporter.error('sPath=%s type=%s: directoryExists returned %s, expected %s!'
4464 % (oFsObj.sPath, type(oFsObj), fExistsResult, fDirExists));
4465
4466 fRc = oTest.closeSession() and fRc;
4467 return (fRc, oTxsSession);
4468
4469 def testGuestCtrlFileOpen(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4470 """
4471 Tests opening guest files.
4472 """
4473 if self.oTstDrv.fpApiVer < 5.0:
4474 reporter.log('Skipping because of pre 5.0 API');
4475 return None;
4476
4477 #
4478 # Paths.
4479 #
4480 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
4481 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
4482 asFiles = [
4483 oTestVm.pathJoin(sTempDir, 'file-open-0'),
4484 oTestVm.pathJoin(sTempDir, 'file-open-1'),
4485 oTestVm.pathJoin(sTempDir, 'file-open-2'),
4486 oTestVm.pathJoin(sTempDir, 'file-open-3'),
4487 oTestVm.pathJoin(sTempDir, 'file-open-4'),
4488 ];
4489 asNonEmptyFiles = [
4490 oTestVm.pathJoin(sTempDir, 'file-open-10'),
4491 oTestVm.pathJoin(sTempDir, 'file-open-11'),
4492 oTestVm.pathJoin(sTempDir, 'file-open-12'),
4493 oTestVm.pathJoin(sTempDir, 'file-open-13'),
4494 ];
4495 sContent = 'abcdefghijklmnopqrstuvwxyz0123456789';
4496 for sFile in asNonEmptyFiles:
4497 if oTxsSession.syncUploadString(sContent, sFile, 0o666) is not True:
4498 return reporter.error('Failed to create "%s" via TXS' % (sFile,));
4499
4500 #
4501 # The tests.
4502 #
4503 atTests = [
4504 # Invalid stuff.
4505 [ tdTestFileOpen(sFile = ''), tdTestResultFailure() ],
4506 # Wrong open mode.
4507 [ tdTestFileOpen(sFile = sFileForReading, eAccessMode = -1), tdTestResultFailure() ],
4508 # Wrong disposition.
4509 [ tdTestFileOpen(sFile = sFileForReading, eAction = -1), tdTestResultFailure() ],
4510 # Non-existing file or path.
4511 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir')), tdTestResultFailure() ],
4512 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4513 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4514 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4515 eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4516 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4517 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-file-or-dir'),
4518 eAccessMode = vboxcon.FileAccessMode_ReadWrite,
4519 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultFailure() ],
4520 [ tdTestFileOpen(sFile = oTestVm.pathJoin(sTempDir, 'no-such-dir', 'no-such-file')), tdTestResultFailure() ],
4521 ];
4522 if self.oTstDrv.fpApiVer > 5.2: # Fixed since 6.0.
4523 atTests.extend([
4524 # Wrong type:
4525 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
4526 [ tdTestFileOpen(sFile = self.oTstDrv.getGuestSystemDir(oTestVm)), tdTestResultFailure() ],
4527 ]);
4528 atTests.extend([
4529 # O_EXCL and such:
4530 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew,
4531 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
4532 [ tdTestFileOpen(sFile = sFileForReading, eAction = vboxcon.FileOpenAction_CreateNew), tdTestResultFailure() ],
4533 # Open a file.
4534 [ tdTestFileOpen(sFile = sFileForReading), tdTestResultSuccess() ],
4535 [ tdTestFileOpen(sFile = sFileForReading,
4536 eAction = vboxcon.FileOpenAction_OpenOrCreate), tdTestResultSuccess() ],
4537 # Create a new file.
4538 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
4539 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4540 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateNew,
4541 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultFailure() ],
4542 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExisting,
4543 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4544 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4545 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4546 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenOrCreate,
4547 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4548 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_OpenExistingTruncated,
4549 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4550 [ tdTestFileOpenCheckSize(sFile = asFiles[0], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4551 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4552 # Open or create a new file.
4553 [ tdTestFileOpenCheckSize(sFile = asFiles[1], eAction = vboxcon.FileOpenAction_OpenOrCreate,
4554 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4555 # Create or replace a new file.
4556 [ tdTestFileOpenCheckSize(sFile = asFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4557 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4558 # Create and append to file (weird stuff).
4559 [ tdTestFileOpenCheckSize(sFile = asFiles[3], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4560 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4561 [ tdTestFileOpenCheckSize(sFile = asFiles[4], eAction = vboxcon.FileOpenAction_AppendOrCreate,
4562 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4563 # Open the non-empty files in non-destructive modes.
4564 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent)), tdTestResultSuccess() ],
4565 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4566 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4567 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4568 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4569
4570 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
4571 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4572 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4573 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4574 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4575 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4576 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4577 eAction = vboxcon.FileOpenAction_OpenOrCreate,
4578 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4579
4580 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], cbOpenExpected = len(sContent),
4581 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4582 eAccessMode = vboxcon.FileAccessMode_ReadWrite), tdTestResultSuccess() ],
4583 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], cbOpenExpected = len(sContent),
4584 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4585 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4586 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], cbOpenExpected = len(sContent),
4587 eAction = vboxcon.FileOpenAction_AppendOrCreate,
4588 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4589
4590 # Now the destructive stuff:
4591 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[0], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4592 eAction = vboxcon.FileOpenAction_OpenExistingTruncated), tdTestResultSuccess() ],
4593 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[1], eAccessMode = vboxcon.FileAccessMode_WriteOnly,
4594 eAction = vboxcon.FileOpenAction_CreateOrReplace), tdTestResultSuccess() ],
4595 [ tdTestFileOpenCheckSize(sFile = asNonEmptyFiles[2], eAction = vboxcon.FileOpenAction_CreateOrReplace,
4596 eAccessMode = vboxcon.FileAccessMode_WriteOnly), tdTestResultSuccess() ],
4597 ]);
4598
4599 #
4600 # Do the testing.
4601 #
4602 fRc = True;
4603 for (i, tTest) in enumerate(atTests):
4604 oCurTest = tTest[0] # type: tdTestFileOpen
4605 oCurRes = tTest[1] # type: tdTestResult
4606
4607 reporter.log('Testing #%d: %s - sFile="%s", eAccessMode=%d, eAction=%d, (%s, %s, %s) ...'
4608 % (i, oCurTest.__class__.__name__, oCurTest.sFile, oCurTest.eAccessMode, oCurTest.eAction,
4609 oCurTest.eSharing, oCurTest.fCreationMode, oCurTest.afOpenFlags,));
4610
4611 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4612 if not fRc:
4613 break;
4614 fRc, _ = oCurTest.createSession('testGuestCtrlFileOpen: Test #%d' % (i,));
4615 if fRc is not True:
4616 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
4617 break;
4618
4619 fRc2 = oCurTest.doSteps(oCurRes.fRc, self);
4620 if fRc2 != oCurRes.fRc:
4621 fRc = reporter.error('Test #%d result mismatch: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
4622
4623 fRc = oCurTest.closeSession() and fRc;
4624
4625 return (fRc, oTxsSession);
4626
4627
4628 def testGuestCtrlFileRead(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-branches,too-many-statements
4629 """
4630 Tests reading from guest files.
4631 """
4632 if self.oTstDrv.fpApiVer < 5.0:
4633 reporter.log('Skipping because of pre 5.0 API');
4634 return None;
4635
4636 #
4637 # Do everything in one session.
4638 #
4639 oTest = tdTestGuestCtrlBase();
4640 fRc = oTest.setEnvironment(oSession, oTxsSession, oTestVm);
4641 if not fRc:
4642 return (False, oTxsSession);
4643 fRc2, oGuestSession = oTest.createSession('FsStat on TestFileSet');
4644 if fRc2 is not True:
4645 return (False, oTxsSession);
4646
4647 #
4648 # Create a really big zero filled, up to 1 GiB, adding it to the list of
4649 # files from the set.
4650 #
4651 # Note! This code sucks a bit because we don't have a working setSize nor
4652 # any way to figure out how much free space there is in the guest.
4653 #
4654 aoExtraFiles = [];
4655 sBigName = self.oTestFiles.generateFilenameEx();
4656 sBigPath = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sBigName);
4657 fRc = True;
4658 try:
4659 oFile = oGuestSession.fileOpenEx(sBigPath, vboxcon.FileAccessMode_ReadWrite, vboxcon.FileOpenAction_CreateOrReplace,
4660 vboxcon.FileSharingMode_All, 0, []);
4661 except:
4662 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4663 else:
4664 # Does setSize work now?
4665 fUseFallback = True;
4666 try:
4667 oFile.setSize(0);
4668 oFile.setSize(64);
4669 fUseFallback = False;
4670 except:
4671 reporter.logXcpt();
4672
4673 # Grow the file till we hit trouble, typical VERR_DISK_FULL, then
4674 # reduce the file size if we have a working setSize.
4675 cbBigFile = 0;
4676 while cbBigFile < (1024 + 32)*1024*1024:
4677 if not fUseFallback:
4678 cbBigFile += 16*1024*1024;
4679 try:
4680 oFile.setSize(cbBigFile);
4681 except Exception:
4682 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4683 try:
4684 cbBigFile -= 16*1024*1024;
4685 oFile.setSize(cbBigFile);
4686 except:
4687 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4688 break;
4689 else:
4690 cbBigFile += 32*1024*1024;
4691 try:
4692 oFile.seek(cbBigFile, vboxcon.FileSeekOrigin_Begin);
4693 oFile.write(bytearray(1), 60*1000);
4694 except:
4695 reporter.logXcpt('cbBigFile=%s' % (sBigPath,));
4696 break;
4697 try:
4698 cbBigFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4699 except:
4700 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4701 try:
4702 oFile.close();
4703 except:
4704 fRc = reporter.errorXcpt('sBigName=%s' % (sBigPath,));
4705 if fRc is True:
4706 reporter.log('Big file: %s bytes: %s' % (cbBigFile, sBigPath,));
4707 aoExtraFiles.append(testfileset.TestFileZeroFilled(None, sBigPath, cbBigFile));
4708 else:
4709 try:
4710 oGuestSession.fsObjRemove(sBigPath);
4711 except:
4712 reporter.errorXcpt('fsObjRemove(sBigName=%s)' % (sBigPath,));
4713
4714 #
4715 # Open and read all the files in the test file set.
4716 #
4717 for oTestFile in aoExtraFiles + self.oTestFiles.aoFiles: # type: testfileset.TestFile
4718 reporter.log2('Test file: %s bytes, "%s" ...' % (oTestFile.cbContent, limitString(oTestFile.sPath),));
4719
4720 #
4721 # Open it:
4722 #
4723 try:
4724 oFile = oGuestSession.fileOpenEx(oTestFile.sPath, vboxcon.FileAccessMode_ReadOnly,
4725 vboxcon.FileOpenAction_OpenExisting, vboxcon.FileSharingMode_All, 0, []);
4726 except:
4727 fRc = reporter.errorXcpt('sPath=%s' % (oTestFile.sPath, ));
4728 continue;
4729
4730 #
4731 # Read the file in different sized chunks:
4732 #
4733 if oTestFile.cbContent < 128:
4734 acbChunks = xrange(1,128);
4735 elif oTestFile.cbContent < 1024:
4736 acbChunks = (2048, 127, 63, 32, 29, 17, 16, 15, 9);
4737 elif oTestFile.cbContent < 8*1024*1024:
4738 acbChunks = (128*1024, 32*1024, 8191, 255);
4739 else:
4740 acbChunks = (768*1024, 128*1024);
4741
4742 reporter.log2('Chunked reads');
4743
4744 for cbChunk in acbChunks:
4745 # Read the whole file straight thru:
4746 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... cbChunk=%s' % (cbChunk,));
4747 offFile = 0;
4748 cReads = 0;
4749 while offFile <= oTestFile.cbContent:
4750 try:
4751 abRead = oFile.read(cbChunk, 30*1000);
4752 except:
4753 fRc = reporter.errorXcpt('%s: offFile=%s cbChunk=%s cbContent=%s'
4754 % (oTestFile.sPath, offFile, cbChunk, oTestFile.cbContent));
4755 break;
4756 cbRead = len(abRead);
4757 if cbRead == 0 and offFile == oTestFile.cbContent:
4758 break;
4759 if cbRead <= 0:
4760 fRc = reporter.error('%s @%s: cbRead=%s, cbContent=%s'
4761 % (oTestFile.sPath, offFile, cbRead, oTestFile.cbContent));
4762 break;
4763 if not oTestFile.equalMemory(abRead, offFile):
4764 fRc = reporter.error('%s: read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead));
4765 break;
4766 offFile += cbRead;
4767 cReads += 1;
4768 if cReads > 8192:
4769 break;
4770
4771 # Seek to start of file.
4772 try:
4773 offFile = oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4774 except:
4775 fRc = reporter.errorXcpt('%s: error seeking to start of file' % (oTestFile.sPath,));
4776 break;
4777 if offFile != 0:
4778 fRc = reporter.error('%s: seek to start of file returned %u, expected 0' % (oTestFile.sPath, offFile));
4779 break;
4780
4781 #
4782 # Random reads.
4783 #
4784 reporter.log2('Random reads (seek)');
4785 for _ in xrange(8):
4786 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4787 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4788 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s' % (offFile, cbToRead,));
4789
4790 try:
4791 offActual = oFile.seek(offFile, vboxcon.FileSeekOrigin_Begin);
4792 except:
4793 fRc = reporter.errorXcpt('%s: error seeking to %s' % (oTestFile.sPath, offFile));
4794 break;
4795 if offActual != offFile:
4796 fRc = reporter.error('%s: seek(%s,Begin) -> %s, expected %s'
4797 % (oTestFile.sPath, offFile, offActual, offFile));
4798 break;
4799
4800 try:
4801 abRead = oFile.read(cbToRead, 30*1000);
4802 except:
4803 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4804 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4805 cbRead = 0;
4806 else:
4807 cbRead = len(abRead);
4808 if not oTestFile.equalMemory(abRead, offFile):
4809 fRc = reporter.error('%s: random read mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4810
4811 try:
4812 offActual = oFile.offset;
4813 except:
4814 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4815 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4816 else:
4817 if offActual != offFile + cbRead:
4818 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4819 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4820 try:
4821 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4822 except:
4823 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#1)'
4824 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4825 else:
4826 if offActual != offFile + cbRead:
4827 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#1)'
4828 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4829
4830 #
4831 # Random reads using readAt.
4832 #
4833 reporter.log2('Random reads (readAt)');
4834 for _ in xrange(12):
4835 offFile = self.oTestFiles.oRandom.randrange(0, oTestFile.cbContent + 1024);
4836 cbToRead = self.oTestFiles.oRandom.randrange(1, min(oTestFile.cbContent + 256, 768*1024));
4837 #if oTestFile.cbContent >= 1024*1024: reporter.log2('... %s LB %s (readAt)' % (offFile, cbToRead,));
4838
4839 try:
4840 abRead = oFile.readAt(offFile, cbToRead, 30*1000);
4841 except:
4842 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s'
4843 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4844 cbRead = 0;
4845 else:
4846 cbRead = len(abRead);
4847 if not oTestFile.equalMemory(abRead, offFile):
4848 fRc = reporter.error('%s: random readAt mismatch @ %s LB %s' % (oTestFile.sPath, offFile, cbRead,));
4849
4850 try:
4851 offActual = oFile.offset;
4852 except:
4853 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4854 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4855 else:
4856 if offActual != offFile + cbRead:
4857 fRc = reporter.error('%s: IFile.offset is %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4858 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4859
4860 try:
4861 offActual = oFile.seek(0, vboxcon.FileSeekOrigin_Current);
4862 except:
4863 fRc = reporter.errorXcpt('%s: offFile=%s cbToRead=%s cbContent=%s (#2)'
4864 % (oTestFile.sPath, offFile, cbToRead, oTestFile.cbContent));
4865 else:
4866 if offActual != offFile + cbRead:
4867 fRc = reporter.error('%s: seek(0,cur) -> %s, expected %s (offFile=%s cbToRead=%s cbRead=%s) (#2)'
4868 % (oTestFile.sPath, offActual, offFile + cbRead, offFile, cbToRead, cbRead));
4869
4870 #
4871 # A few negative things.
4872 #
4873
4874 # Zero byte reads -> E_INVALIDARG.
4875 reporter.log2('Zero byte reads');
4876 try:
4877 abRead = oFile.read(0, 30*1000);
4878 except Exception as oXcpt:
4879 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4880 fRc = reporter.errorXcpt('read(0,30s) did not raise E_INVALIDARG as expected!');
4881 else:
4882 fRc = reporter.error('read(0,30s) did not fail!');
4883
4884 try:
4885 abRead = oFile.readAt(0, 0, 30*1000);
4886 except Exception as oXcpt:
4887 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_INVALIDARG):
4888 fRc = reporter.errorXcpt('readAt(0,0,30s) did not raise E_INVALIDARG as expected!');
4889 else:
4890 fRc = reporter.error('readAt(0,0,30s) did not fail!');
4891
4892 # See what happens when we read 1GiB. We should get a max of 1MiB back.
4893 ## @todo Document this behaviour in VirtualBox.xidl.
4894 reporter.log2('1GB reads');
4895 try:
4896 oFile.seek(0, vboxcon.FileSeekOrigin_Begin);
4897 except:
4898 fRc = reporter.error('seek(0)');
4899 try:
4900 abRead = oFile.read(1024*1024*1024, 30*1000);
4901 except:
4902 fRc = reporter.errorXcpt('read(1GiB,30s)');
4903 else:
4904 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4905 fRc = reporter.error('Expected read(1GiB,30s) to return %s bytes, got %s bytes instead'
4906 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4907
4908 try:
4909 abRead = oFile.readAt(0, 1024*1024*1024, 30*1000);
4910 except:
4911 fRc = reporter.errorXcpt('readAt(0,1GiB,30s)');
4912 else:
4913 if len(abRead) != min(oTestFile.cbContent, 1024*1024):
4914 reporter.error('Expected readAt(0, 1GiB,30s) to return %s bytes, got %s bytes instead'
4915 % (min(oTestFile.cbContent, 1024*1024), len(abRead),));
4916
4917 #
4918 # Check stat info on the file as well as querySize.
4919 #
4920 if self.oTstDrv.fpApiVer > 5.2:
4921 try:
4922 oFsObjInfo = oFile.queryInfo();
4923 except:
4924 fRc = reporter.errorXcpt('%s: queryInfo()' % (oTestFile.sPath,));
4925 else:
4926 if oFsObjInfo is None:
4927 fRc = reporter.error('IGuestFile::queryInfo returned None');
4928 else:
4929 try:
4930 cbFile = oFsObjInfo.objectSize;
4931 except:
4932 fRc = reporter.errorXcpt();
4933 else:
4934 if cbFile != oTestFile.cbContent:
4935 fRc = reporter.error('%s: queryInfo returned incorrect file size: %s, expected %s'
4936 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4937
4938 try:
4939 cbFile = oFile.querySize();
4940 except:
4941 fRc = reporter.errorXcpt('%s: querySize()' % (oTestFile.sPath,));
4942 else:
4943 if cbFile != oTestFile.cbContent:
4944 fRc = reporter.error('%s: querySize returned incorrect file size: %s, expected %s'
4945 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4946
4947 #
4948 # Use seek to test the file size and do a few other end-relative seeks.
4949 #
4950 try:
4951 cbFile = oFile.seek(0, vboxcon.FileSeekOrigin_End);
4952 except:
4953 fRc = reporter.errorXcpt('%s: seek(0,End)' % (oTestFile.sPath,));
4954 else:
4955 if cbFile != oTestFile.cbContent:
4956 fRc = reporter.error('%s: seek(0,End) returned incorrect file size: %s, expected %s'
4957 % (oTestFile.sPath, cbFile, oTestFile.cbContent));
4958 if oTestFile.cbContent > 0:
4959 for _ in xrange(5):
4960 offSeek = self.oTestFiles.oRandom.randrange(oTestFile.cbContent + 1);
4961 try:
4962 offFile = oFile.seek(-offSeek, vboxcon.FileSeekOrigin_End);
4963 except:
4964 fRc = reporter.errorXcpt('%s: seek(%s,End)' % (oTestFile.sPath, -offSeek,));
4965 else:
4966 if offFile != oTestFile.cbContent - offSeek:
4967 fRc = reporter.error('%s: seek(%s,End) returned incorrect offset: %s, expected %s (cbContent=%s)'
4968 % (oTestFile.sPath, -offSeek, offSeek, oTestFile.cbContent - offSeek,
4969 oTestFile.cbContent,));
4970
4971 #
4972 # Close it and we're done with this file.
4973 #
4974 try:
4975 oFile.close();
4976 except:
4977 fRc = reporter.errorXcpt('%s: error closing the file' % (oTestFile.sPath,));
4978
4979 #
4980 # Clean up.
4981 #
4982 for oTestFile in aoExtraFiles:
4983 try:
4984 oGuestSession.fsObjRemove(sBigPath);
4985 except:
4986 fRc = reporter.errorXcpt('fsObjRemove(%s)' % (sBigPath,));
4987
4988 fRc = oTest.closeSession() and fRc;
4989
4990 return (fRc, oTxsSession);
4991
4992
4993 def testGuestCtrlFileWrite(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
4994 """
4995 Tests writing to guest files.
4996 """
4997 if self.oTstDrv.fpApiVer < 5.0:
4998 reporter.log('Skipping because of pre 5.0 API');
4999 return None;
5000
5001 #
5002 # The test file and its content.
5003 #
5004 sFile = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'gctrl-write-1');
5005 abContent = bytearray(0);
5006
5007 #
5008 # The tests.
5009 #
5010 def randBytes(cbHowMany):
5011 """ Returns an bytearray of random bytes. """
5012 return bytearray(self.oTestFiles.oRandom.getrandbits(8) for _ in xrange(cbHowMany));
5013
5014 aoTests = [
5015 # Write at end:
5016 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_CreateNew, abContent = abContent,
5017 atChunks = [(None, randBytes(1)), (None, randBytes(77)), (None, randBytes(98)),]),
5018 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1+77+98), # 176
5019 # Appending:
5020 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
5021 atChunks = [(None, randBytes(255)), (None, randBytes(33)),]),
5022 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 176 + 255+33), # 464
5023 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_AppendOrCreate, abContent = abContent,
5024 atChunks = [(10, randBytes(44)),]),
5025 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 464 + 44), # 508
5026 # Write within existing:
5027 tdTestFileOpenAndWrite(sFile = sFile, eAction = vboxcon.FileOpenAction_OpenExisting, abContent = abContent,
5028 atChunks = [(0, randBytes(1)), (50, randBytes(77)), (255, randBytes(199)),]),
5029 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 508),
5030 # Writing around and over the end:
5031 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent,
5032 atChunks = [(500, randBytes(9)), (508, randBytes(15)), (512, randBytes(12)),]),
5033 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 512+12),
5034
5035 # writeAt appending:
5036 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5037 atChunks = [(0, randBytes(23)), (6, randBytes(1018)),]),
5038 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 6+1018), # 1024
5039 # writeAt within existing:
5040 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5041 atChunks = [(1000, randBytes(23)), (1, randBytes(990)),]),
5042 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1024),
5043 # writeAt around and over the end:
5044 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True,
5045 atChunks = [(1024, randBytes(63)), (1080, randBytes(968)),]),
5046 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 1080+968), # 2048
5047
5048 # writeAt beyond the end (gap is filled with zeros):
5049 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, fUseAtApi = True, atChunks = [(3070, randBytes(2)),]),
5050 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 3072),
5051 # write beyond the end (gap is filled with zeros):
5052 tdTestFileOpenAndWrite(sFile = sFile, abContent = abContent, atChunks = [(4090, randBytes(6)),]),
5053 tdTestFileOpenAndCheckContent(sFile = sFile, abContent = abContent, cbContentExpected = 4096),
5054 ];
5055
5056 for (i, oCurTest) in enumerate(aoTests):
5057 reporter.log('Testing #%d: %s ...' % (i, oCurTest.toString(),));
5058 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5059 if not fRc:
5060 break;
5061 fRc, _ = oCurTest.createSession('testGuestCtrlFileWrite: Test #%d' % (i,));
5062 if fRc is not True:
5063 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5064 break;
5065
5066 fRc2 = oCurTest.doSteps(True, self);
5067 if fRc2 is not True:
5068 fRc = reporter.error('Test #%d failed!' % (i,));
5069
5070 fRc = oCurTest.closeSession() and fRc;
5071
5072 #
5073 # Cleanup
5074 #
5075 if oTxsSession.syncRmFile(sFile) is not True:
5076 fRc = reporter.error('Failed to remove write-test file: %s' % (sFile, ));
5077
5078 return (fRc, oTxsSession);
5079
5080 @staticmethod
5081 def __generateFile(sName, cbFile):
5082 """ Helper for generating a file with a given size. """
5083 with open(sName, 'wb') as oFile:
5084 while cbFile > 0:
5085 cb = cbFile if cbFile < 256*1024 else 256*1024;
5086 oFile.write(bytearray(random.getrandbits(8) for _ in xrange(cb)));
5087 cbFile -= cb;
5088 return True;
5089
5090 def testGuestCtrlCopyTo(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5091 """
5092 Tests copying files from host to the guest.
5093 """
5094
5095 #
5096 # Paths and test files.
5097 #
5098 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, 'copyto');
5099 sScratchTestFilesHst = os.path.join(sScratchHst, self.oTestFiles.sSubDir);
5100 sScratchEmptyDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oEmptyDir.sName);
5101 sScratchNonEmptyDirHst = self.oTestFiles.chooseRandomDirFromTree().buildPath(sScratchHst, os.path.sep);
5102 sScratchTreeDirHst = os.path.join(sScratchTestFilesHst, self.oTestFiles.oTreeDir.sName);
5103
5104 sScratchGst = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'copyto');
5105 sScratchDstDir1Gst = oTestVm.pathJoin(sScratchGst, 'dstdir1');
5106 sScratchDstDir2Gst = oTestVm.pathJoin(sScratchGst, 'dstdir2');
5107 sScratchDstDir3Gst = oTestVm.pathJoin(sScratchGst, 'dstdir3');
5108 sScratchDstDir4Gst = oTestVm.pathJoin(sScratchGst, 'dstdir4');
5109 sScratchDotDotDirGst = oTestVm.pathJoin(sScratchGst, '..');
5110 #sScratchGstNotExist = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-file-or-directory');
5111 sScratchHstNotExist = os.path.join(self.oTstDrv.sScratchPath, 'no-such-file-or-directory');
5112 sScratchGstPathNotFound = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'no-such-directory', 'or-file');
5113 #sScratchHstPathNotFound = os.path.join(self.oTstDrv.sScratchPath, 'no-such-directory', 'or-file');
5114
5115 if oTestVm.isWindows() or oTestVm.isOS2():
5116 sScratchGstInvalid = "?*|<invalid-name>";
5117 else:
5118 sScratchGstInvalid = None;
5119 if utils.getHostOs() in ('win', 'os2'):
5120 sScratchHstInvalid = "?*|<invalid-name>";
5121 else:
5122 sScratchHstInvalid = None;
5123
5124 for sDir in (sScratchGst, sScratchDstDir1Gst, sScratchDstDir2Gst, sScratchDstDir3Gst, sScratchDstDir4Gst):
5125 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
5126 return reporter.error('TXS failed to create directory "%s"!' % (sDir,));
5127
5128 # Put the test file set under sScratchHst.
5129 if os.path.exists(sScratchHst):
5130 if base.wipeDirectory(sScratchHst) != 0:
5131 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
5132 else:
5133 try:
5134 os.mkdir(sScratchHst);
5135 except:
5136 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
5137 if self.oTestFiles.writeToDisk(sScratchHst) is not True:
5138 return reporter.error('Filed to write test files to "%s" on the host!' % (sScratchHst,));
5139
5140 # If for whatever reason the directory tree does not exist on the host, let us know.
5141 # Copying an non-existing tree *will* fail the tests which otherwise should succeed!
5142 assert os.path.exists(sScratchTreeDirHst);
5143
5144 # Generate a test file in 32MB to 64 MB range.
5145 sBigFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-random.data');
5146 cbBigFileHst = random.randrange(32*1024*1024, 64*1024*1024);
5147 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
5148 cbLeft = cbBigFileHst;
5149 try:
5150 self.__generateFile(sBigFileHst, cbBigFileHst);
5151 except:
5152 return reporter.errorXcpt('sBigFileHst=%s cbBigFileHst=%s cbLeft=%s' % (sBigFileHst, cbBigFileHst, cbLeft,));
5153 reporter.log('cbBigFileHst=%s' % (cbBigFileHst,));
5154
5155 # Generate an empty file on the host that we can use to save space in the guest.
5156 sEmptyFileHst = os.path.join(self.oTstDrv.sScratchPath, 'gctrl-empty.data');
5157 try:
5158 open(sEmptyFileHst, "wb").close(); # pylint: disable=consider-using-with
5159 except:
5160 return reporter.errorXcpt('sEmptyFileHst=%s' % (sEmptyFileHst,));
5161
5162 # os.path.join() is too clever for "..", so we just build up the path here ourselves.
5163 sScratchDotDotFileHst = sScratchHst + os.path.sep + '..' + os.path.sep + 'gctrl-empty.data';
5164
5165 #
5166 # Tests.
5167 #
5168 atTests = [
5169 # Nothing given:
5170 [ tdTestCopyToFile(), tdTestResultFailure() ],
5171 [ tdTestCopyToDir(), tdTestResultFailure() ],
5172 # Only source given:
5173 [ tdTestCopyToFile(sSrc = sBigFileHst), tdTestResultFailure() ],
5174 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst), tdTestResultFailure() ],
5175 # Only destination given:
5176 [ tdTestCopyToFile(sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')), tdTestResultFailure() ],
5177 [ tdTestCopyToDir( sDst = sScratchGst), tdTestResultFailure() ],
5178 # Both given, but invalid flags.
5179 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst, afFlags = [ 0x40000000, ] ), tdTestResultFailure() ],
5180 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGst, afFlags = [ 0x40000000, ] ),
5181 tdTestResultFailure() ],
5182 ];
5183 atTests.extend([
5184 # Non-existing source, but no destination:
5185 [ tdTestCopyToFile(sSrc = sScratchHstNotExist), tdTestResultFailure() ],
5186 [ tdTestCopyToDir( sSrc = sScratchHstNotExist), tdTestResultFailure() ],
5187 # Valid sources, but destination path not found:
5188 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
5189 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = sScratchGstPathNotFound), tdTestResultFailure() ],
5190 # Valid destination, but source file/dir not found:
5191 [ tdTestCopyToFile(sSrc = sScratchHstNotExist, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
5192 tdTestResultFailure() ],
5193 [ tdTestCopyToDir( sSrc = sScratchHstNotExist, sDst = sScratchGst), tdTestResultFailure() ],
5194 # Wrong type:
5195 [ tdTestCopyToFile(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, 'dstfile')),
5196 tdTestResultFailure() ],
5197 [ tdTestCopyToDir( sSrc = sBigFileHst, sDst = sScratchGst), tdTestResultFailure() ],
5198 ]);
5199 # Invalid characters in destination or source path:
5200 if sScratchGstInvalid is not None:
5201 atTests.extend([
5202 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
5203 tdTestResultFailure() ],
5204 [ tdTestCopyToDir( sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchGst, sScratchGstInvalid)),
5205 tdTestResultFailure() ],
5206 ]);
5207 if sScratchHstInvalid is not None:
5208 atTests.extend([
5209 [ tdTestCopyToFile(sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
5210 tdTestResultFailure() ],
5211 [ tdTestCopyToDir( sSrc = os.path.join(self.oTstDrv.sScratchPath, sScratchHstInvalid), sDst = sScratchGst),
5212 tdTestResultFailure() ],
5213 ]);
5214
5215 #
5216 # Single file handling.
5217 #
5218 atTests.extend([
5219 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')),
5220 tdTestResultSuccess() ],
5221 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
5222 tdTestResultSuccess() ],
5223 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat')), # Overwrite
5224 tdTestResultSuccess() ],
5225 ]);
5226 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
5227 atTests.extend([
5228 # Should succeed, as the file isn't there yet on the destination.
5229 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst + oTestVm.pathSep()), tdTestResultSuccess() ],
5230 # Overwrite the existing file.
5231 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = sScratchGst + oTestVm.pathSep()), tdTestResultSuccess() ],
5232 # Same file, but with a different name on the destination.
5233 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, os.path.split(sBigFileHst)[1])),
5234 tdTestResultSuccess() ], # Overwrite
5235 ]);
5236
5237 if oTestVm.isWindows():
5238 # Copy to a Windows alternative data stream (ADS).
5239 atTests.extend([
5240 [ tdTestCopyToFile(sSrc = sBigFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
5241 tdTestResultSuccess() ],
5242 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = oTestVm.pathJoin(sScratchGst, 'HostGABig.dat:ADS-Test')),
5243 tdTestResultSuccess() ],
5244 ]);
5245
5246 #
5247 # Directory handling.
5248 #
5249 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
5250 atTests.extend([
5251 # Without a trailing slash added to the destination this should fail,
5252 # as the destination directory already exists.
5253 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst), tdTestResultFailure() ],
5254 # Same existing host directory, but this time with DirectoryCopyFlag_CopyIntoExisting set.
5255 # This should copy the contents of oEmptyDirGst to sScratchDstDir1Gst (empty, but anyway).
5256 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
5257 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5258 # Try again.
5259 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir1Gst,
5260 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5261 # With a trailing slash added to the destination, copy the empty guest directory
5262 # (should end up as sScratchDstDir2Gst/empty):
5263 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
5264 tdTestResultSuccess() ],
5265 # Repeat -- this time it should fail, as the destination directory already exists (and
5266 # DirectoryCopyFlag_CopyIntoExisting is not specified):
5267 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep()),
5268 tdTestResultFailure() ],
5269 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work (again).
5270 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = sScratchDstDir2Gst + oTestVm.pathSep(),
5271 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5272 # Copy with a different destination name just for the heck of it:
5273 [ tdTestCopyToDir(sSrc = sScratchEmptyDirHst, sDst = oTestVm.pathJoin(sScratchDstDir2Gst, 'empty2')),
5274 tdTestResultSuccess() ],
5275 ]);
5276 atTests.extend([
5277 # Now the same using a directory with files in it:
5278 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
5279 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5280 # Again.
5281 [ tdTestCopyToDir(sSrc = sScratchNonEmptyDirHst, sDst = sScratchDstDir3Gst,
5282 afFlags = [vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5283 ]);
5284 atTests.extend([
5285 # Copy the entire test tree:
5286 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep()),
5287 tdTestResultSuccess() ],
5288 # Again, should fail this time.
5289 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep()),
5290 tdTestResultFailure() ],
5291 # Works again, as DirectoryCopyFlag_CopyIntoExisting is specified.
5292 [ tdTestCopyToDir(sSrc = sScratchTreeDirHst, sDst = sScratchDstDir4Gst + oTestVm.pathSep(),
5293 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5294 ]);
5295 #
5296 # Dotdot path handling.
5297 #
5298 if self.oTstDrv.fpApiVer >= 6.1:
5299 atTests.extend([
5300 # Test if copying stuff from a host dotdot ".." directory works.
5301 [ tdTestCopyToFile(sSrc = sScratchDotDotFileHst, sDst = sScratchDstDir1Gst + oTestVm.pathSep()),
5302 tdTestResultSuccess() ],
5303 # Test if copying stuff from the host to a guest's dotdot ".." directory works.
5304 # That should fail on destinations.
5305 [ tdTestCopyToFile(sSrc = sEmptyFileHst, sDst = sScratchDotDotDirGst), tdTestResultFailure() ],
5306 ]);
5307
5308 fRc = True;
5309 for (i, tTest) in enumerate(atTests):
5310 oCurTest = tTest[0]; # tdTestCopyTo
5311 oCurRes = tTest[1]; # tdTestResult
5312 reporter.log('Testing #%d, sSrc=%s, sDst=%s, afFlags=%s ...'
5313 % (i, limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags));
5314
5315 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5316 if not fRc:
5317 break;
5318 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyTo: Test #%d' % (i,));
5319 if fRc is not True:
5320 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5321 break;
5322
5323 fRc2 = False;
5324 if isinstance(oCurTest, tdTestCopyToFile):
5325 fRc2 = self.gctrlCopyFileTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
5326 else:
5327 fRc2 = self.gctrlCopyDirTo(oCurGuestSession, oCurTest.sSrc, oCurTest.sDst, oCurTest.afFlags, oCurRes.fRc);
5328 if fRc2 is not oCurRes.fRc:
5329 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
5330
5331 fRc = oCurTest.closeSession() and fRc;
5332
5333 return (fRc, oTxsSession);
5334
5335 def testGuestCtrlCopyFrom(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5336 """
5337 Tests copying files from guest to the host.
5338 """
5339
5340 reporter.log2('Entered');
5341
5342 #
5343 # Paths.
5344 #
5345 sScratchHst = os.path.join(self.oTstDrv.sScratchPath, "testGctrlCopyFrom");
5346 sScratchDstDir1Hst = os.path.join(sScratchHst, "dstdir1");
5347 sScratchDstDir2Hst = os.path.join(sScratchHst, "dstdir2");
5348 sScratchDstDir3Hst = os.path.join(sScratchHst, "dstdir3");
5349 sScratchDstDir4Hst = os.path.join(sScratchHst, "dstdir4");
5350 # os.path.join() is too clever for "..", so we just build up the path here ourselves.
5351 sScratchDotDotDirHst = sScratchHst + os.path.sep + '..' + os.path.sep;
5352 oExistingFileGst = self.oTestFiles.chooseRandomFile();
5353 oNonEmptyDirGst = self.oTestFiles.chooseRandomDirFromTree(fNonEmpty = True);
5354 oTreeDirGst = self.oTestFiles.oTreeDir;
5355 oEmptyDirGst = self.oTestFiles.oEmptyDir;
5356
5357 if oTestVm.isWindows() or oTestVm.isOS2():
5358 sScratchGstInvalid = "?*|<invalid-name>";
5359 else:
5360 sScratchGstInvalid = None;
5361 if utils.getHostOs() in ('win', 'os2'):
5362 sScratchHstInvalid = "?*|<invalid-name>";
5363 else:
5364 sScratchHstInvalid = None;
5365
5366 sScratchDotDotDirGst = oTestVm.pathJoin(oEmptyDirGst.sPath, '..');
5367
5368 if os.path.exists(sScratchHst):
5369 if base.wipeDirectory(sScratchHst) != 0:
5370 return reporter.error('Failed to wipe "%s"' % (sScratchHst,));
5371 else:
5372 try:
5373 os.mkdir(sScratchHst);
5374 except:
5375 return reporter.errorXcpt('os.mkdir(%s)' % (sScratchHst, ));
5376
5377 reporter.log2('Creating host sub dirs ...');
5378
5379 for sSubDir in (sScratchDstDir1Hst, sScratchDstDir2Hst, sScratchDstDir3Hst, sScratchDstDir4Hst):
5380 try:
5381 os.mkdir(sSubDir);
5382 except:
5383 return reporter.errorXcpt('os.mkdir(%s)' % (sSubDir, ));
5384
5385 reporter.log2('Defining tests ...');
5386
5387 #
5388 # Bad parameter tests.
5389 #
5390 atTests = [
5391 # Missing both source and destination:
5392 [ tdTestCopyFromFile(), tdTestResultFailure() ],
5393 [ tdTestCopyFromDir(), tdTestResultFailure() ],
5394 # Missing source.
5395 [ tdTestCopyFromFile(sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5396 [ tdTestCopyFromDir( sDst = sScratchHst), tdTestResultFailure() ],
5397 # Missing destination.
5398 [ tdTestCopyFromFile(oSrc = oExistingFileGst), tdTestResultFailure() ],
5399 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath), tdTestResultFailure() ],
5400 # Invalid flags:
5401 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somefile'), afFlags = [0x40000000]),
5402 tdTestResultFailure() ],
5403 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'somedir'), afFlags = [ 0x40000000] ),
5404 tdTestResultFailure() ],
5405 # Non-existing sources:
5406 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
5407 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5408 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-file-or-directory'),
5409 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5410 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-file'),
5411 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5412 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'no-such-directory', 'no-such-subdir'),
5413 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5414 # Non-existing destinations:
5415 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
5416 sDst = os.path.join(sScratchHst, 'no-such-directory', 'somefile') ), tdTestResultFailure() ],
5417 [ tdTestCopyFromDir( oSrc = oEmptyDirGst, sDst = os.path.join(sScratchHst, 'no-such-directory', 'somedir') ),
5418 tdTestResultFailure() ],
5419 [ tdTestCopyFromFile(oSrc = oExistingFileGst,
5420 sDst = os.path.join(sScratchHst, 'no-such-directory-slash' + os.path.sep)),
5421 tdTestResultFailure() ],
5422 # Wrong source type:
5423 [ tdTestCopyFromFile(oSrc = oNonEmptyDirGst, sDst = os.path.join(sScratchHst, 'somefile') ), tdTestResultFailure() ],
5424 [ tdTestCopyFromDir(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'somedir') ), tdTestResultFailure() ],
5425 ];
5426 # Bogus names:
5427 if sScratchHstInvalid:
5428 atTests.extend([
5429 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
5430 tdTestResultFailure() ],
5431 [ tdTestCopyFromDir( sSrc = self.oTestFiles.oManyDir.sPath, sDst = os.path.join(sScratchHst, sScratchHstInvalid)),
5432 tdTestResultFailure() ],
5433 ]);
5434 if sScratchGstInvalid:
5435 atTests.extend([
5436 [ tdTestCopyFromFile(sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
5437 sDst = os.path.join(sScratchHst, 'somefile')), tdTestResultFailure() ],
5438 [ tdTestCopyFromDir( sSrc = oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, sScratchGstInvalid),
5439 sDst = os.path.join(sScratchHst, 'somedir')), tdTestResultFailure() ],
5440 ]);
5441
5442 #
5443 # Single file copying.
5444 #
5445 atTests.extend([
5446 # Should succeed, as the file isn't there yet on the destination.
5447 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), tdTestResultSuccess() ],
5448 # Overwrite the existing file.
5449 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile1')), tdTestResultSuccess() ],
5450 # Same file, but with a different name on the destination.
5451 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = os.path.join(sScratchHst, 'copyfile2')), tdTestResultSuccess() ],
5452 ]);
5453
5454 if self.oTstDrv.fpApiVer > 5.2: # Copying files into directories via Main is supported only 6.0 and later.
5455 # Copy into a directory.
5456 atTests.extend([
5457 # This should fail, as sScratchHst exists and is a directory.
5458 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst), tdTestResultFailure() ],
5459 # Same existing host directory, but this time with a trailing slash.
5460 # This should succeed, as the file isn't there yet on the destination.
5461 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
5462 # Overwrite the existing file.
5463 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchHst + os.path.sep), tdTestResultSuccess() ],
5464 ]);
5465
5466 #
5467 # Directory handling.
5468 #
5469 if self.oTstDrv.fpApiVer > 5.2: # Copying directories via Main is supported only in versions > 5.2.
5470 atTests.extend([
5471 # Without a trailing slash added to the destination this should fail,
5472 # as the destination directory already exist.
5473 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst), tdTestResultFailure() ],
5474 # Same existing host directory, but this time with DirectoryCopyFlag_CopyIntoExisting set.
5475 # This should copy the contents of oEmptyDirGst to sScratchDstDir1Hst (empty, but anyway).
5476 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst,
5477 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5478 # Try again.
5479 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = sScratchDstDir1Hst,
5480 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5481 # With a trailing slash added to the destination, copy the empty guest directory
5482 # (should end up as sScratchHst/empty):
5483 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep), tdTestResultSuccess() ],
5484 # Repeat -- this time it should fail, as the destination directory already exists (and
5485 # DirectoryCopyFlag_CopyIntoExisting is not specified):
5486 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep), tdTestResultFailure() ],
5487 # Add the DirectoryCopyFlag_CopyIntoExisting flag being set and it should work (again).
5488 [ tdTestCopyFromDir(oSrc = oEmptyDirGst, sDst = sScratchDstDir2Hst + os.path.sep,
5489 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5490 # Copy with a different destination name just for the heck of it:
5491 [ tdTestCopyFromDir(sSrc = oEmptyDirGst.sPath, sDst = os.path.join(sScratchDstDir2Hst, 'empty2'),
5492 fIntoDst = True),
5493 tdTestResultSuccess() ],
5494 ]);
5495 atTests.extend([
5496 # Now the same using a directory with files in it:
5497 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir3Hst + os.path.sep), tdTestResultSuccess() ],
5498 # Again.
5499 [ tdTestCopyFromDir(oSrc = oNonEmptyDirGst, sDst = sScratchDstDir3Hst, fIntoDst = True,
5500 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5501 ]);
5502 atTests.extend([
5503 # Copy the entire test tree:
5504 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep), tdTestResultSuccess() ],
5505 # Again, should fail this time.
5506 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep), tdTestResultFailure() ],
5507 # Works again, as DirectoryCopyFlag_CopyIntoExisting is specified.
5508 [ tdTestCopyFromDir(oSrc = oTreeDirGst, sDst = sScratchDstDir4Hst + os.path.sep,
5509 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]), tdTestResultSuccess() ],
5510 ]);
5511 #
5512 # Dotdot path handling.
5513 #
5514 if self.oTstDrv.fpApiVer >= 6.1:
5515 atTests.extend([
5516 # Test if copying stuff from a guest dotdot ".." directory works.
5517 [ tdTestCopyFromDir(sSrc = sScratchDotDotDirGst, sDst = sScratchDstDir1Hst + os.path.sep,
5518 afFlags = [ vboxcon.DirectoryCopyFlag_CopyIntoExisting, ]),
5519 tdTestResultFailure() ],
5520 # Test if copying stuff from the guest to a host's dotdot ".." directory works.
5521 # That should fail on destinations.
5522 [ tdTestCopyFromFile(oSrc = oExistingFileGst, sDst = sScratchDotDotDirHst), tdTestResultFailure() ],
5523 ]);
5524
5525 reporter.log2('Executing tests ...');
5526
5527 #
5528 # Execute the tests.
5529 #
5530 fRc = True;
5531 for (i, tTest) in enumerate(atTests):
5532 oCurTest = tTest[0]
5533 oCurRes = tTest[1] # type: tdTestResult
5534 if isinstance(oCurTest, tdTestCopyFrom):
5535 reporter.log('Testing #%d, %s: sSrc="%s", sDst="%s", afFlags="%s" ...'
5536 % (i, "directory" if isinstance(oCurTest, tdTestCopyFromDir) else "file",
5537 limitString(oCurTest.sSrc), limitString(oCurTest.sDst), oCurTest.afFlags,));
5538 else:
5539 reporter.log('Testing #%d, tdTestRemoveHostDir "%s" ...' % (i, oCurTest.sDir,));
5540 if isinstance(oCurTest, tdTestCopyFromDir) and self.oTstDrv.fpApiVer < 6.0:
5541 reporter.log('Skipping directoryCopyFromGuest test, not implemented in %s' % (self.oTstDrv.fpApiVer,));
5542 continue;
5543
5544 if isinstance(oCurTest, tdTestRemoveHostDir):
5545 fRc = oCurTest.execute(self.oTstDrv, oSession, oTxsSession, oTestVm, 'testing #%d' % (i,));
5546 else:
5547 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5548 if not fRc:
5549 break;
5550 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlCopyFrom: Test #%d' % (i,));
5551 if fRc2 is not True:
5552 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5553 break;
5554
5555 if isinstance(oCurTest, tdTestCopyFromFile):
5556 fRc2 = self.gctrlCopyFileFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
5557 else:
5558 fRc2 = self.gctrlCopyDirFrom(oCurGuestSession, oCurTest, oCurRes.fRc);
5559
5560 if fRc2 != oCurRes.fRc:
5561 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
5562
5563 fRc = oCurTest.closeSession() and fRc;
5564
5565 return (fRc, oTxsSession);
5566
5567 def testGuestCtrlUpdateAdditions(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
5568 """
5569 Tests updating the Guest Additions inside the guest.
5570
5571 """
5572
5573 ## @todo currently disabled everywhere.
5574 if self.oTstDrv.fpApiVer < 100.0:
5575 reporter.log("Skipping updating GAs everywhere for now...");
5576 return None;
5577
5578 # Skip test for updating Guest Additions if we run on a too old (Windows) guest.
5579 ##
5580 ## @todo make it work everywhere!
5581 ##
5582 if oTestVm.sKind in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
5583 reporter.log("Skipping updating GAs on old windows vm (sKind=%s)" % (oTestVm.sKind,));
5584 return (None, oTxsSession);
5585 if oTestVm.isOS2():
5586 reporter.log("Skipping updating GAs on OS/2 guest");
5587 return (None, oTxsSession);
5588
5589 sVBoxValidationKitIso = self.oTstDrv.sVBoxValidationKitIso;
5590 if not os.path.isfile(sVBoxValidationKitIso):
5591 return reporter.log('Validation Kit .ISO not found at "%s"' % (sVBoxValidationKitIso,));
5592
5593 sScratch = os.path.join(self.oTstDrv.sScratchPath, "testGctrlUpdateAdditions");
5594 try:
5595 os.makedirs(sScratch);
5596 except OSError as e:
5597 if e.errno != errno.EEXIST:
5598 return reporter.error('Failed: Unable to create scratch directory \"%s\"' % (sScratch,));
5599 reporter.log('Scratch path is: %s' % (sScratch,));
5600
5601 atTests = [];
5602 if oTestVm.isWindows():
5603 atTests.extend([
5604 # Source is missing.
5605 [ tdTestUpdateAdditions(sSrc = ''), tdTestResultFailure() ],
5606
5607 # Wrong flags.
5608 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
5609 afFlags = [ 1234 ]), tdTestResultFailure() ],
5610
5611 # Non-existing .ISO.
5612 [ tdTestUpdateAdditions(sSrc = "non-existing.iso"), tdTestResultFailure() ],
5613
5614 # Wrong .ISO.
5615 [ tdTestUpdateAdditions(sSrc = sVBoxValidationKitIso), tdTestResultFailure() ],
5616
5617 # The real thing.
5618 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso()),
5619 tdTestResultSuccess() ],
5620 # Test the (optional) installer arguments. This will extract the
5621 # installer into our guest's scratch directory.
5622 [ tdTestUpdateAdditions(sSrc = self.oTstDrv.getGuestAdditionsIso(),
5623 asArgs = [ '/extract', '/D=' + sScratch ]),
5624 tdTestResultSuccess() ]
5625 # Some debg ISO. Only enable locally.
5626 #[ tdTestUpdateAdditions(
5627 # sSrc = "V:\\Downloads\\VBoxGuestAdditions-r80354.iso"),
5628 # tdTestResultSuccess() ]
5629 ]);
5630 else:
5631 reporter.log('No OS-specific tests for non-Windows yet!');
5632
5633 fRc = True;
5634 for (i, tTest) in enumerate(atTests):
5635 oCurTest = tTest[0] # type: tdTestUpdateAdditions
5636 oCurRes = tTest[1] # type: tdTestResult
5637 reporter.log('Testing #%d, sSrc="%s", afFlags="%s" ...' % (i, oCurTest.sSrc, oCurTest.afFlags,));
5638
5639 oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
5640 if not fRc:
5641 break;
5642 fRc, _ = oCurTest.createSession('Test #%d' % (i,));
5643 if fRc is not True:
5644 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
5645 break;
5646
5647 try:
5648 oCurProgress = oCurTest.oGuest.updateGuestAdditions(oCurTest.sSrc, oCurTest.asArgs, oCurTest.afFlags);
5649 except:
5650 reporter.maybeErrXcpt(oCurRes.fRc, 'Updating Guest Additions exception for sSrc="%s", afFlags="%s":'
5651 % (oCurTest.sSrc, oCurTest.afFlags,));
5652 fRc = False;
5653 else:
5654 if oCurProgress is not None:
5655 oWrapperProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr,
5656 self.oTstDrv, "gctrlUpGA");
5657 oWrapperProgress.wait();
5658 if not oWrapperProgress.isSuccess():
5659 oWrapperProgress.logResult(fIgnoreErrors = not oCurRes.fRc);
5660 fRc = False;
5661 else:
5662 fRc = reporter.error('No progress object returned');
5663
5664 oCurTest.closeSession();
5665 if fRc is oCurRes.fRc:
5666 if fRc:
5667 ## @todo Verify if Guest Additions were really updated (build, revision, ...).
5668 ## @todo r=bird: Not possible since you're installing the same GAs as before...
5669 ## Maybe check creation dates on certain .sys/.dll/.exe files?
5670 pass;
5671 else:
5672 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc, oCurRes.fRc));
5673 break;
5674
5675 return (fRc, oTxsSession);
5676
5677 def checkScreenShot(self, iWidth, iHeight, aRGBData): # pylint: disable=unused-argument
5678 """
5679 TBD: Implement basic validation of the captured screenshot content.
5680 """
5681 cPixels = iHeight * iWidth
5682
5683 if cPixels == 0:
5684 reporter.logXcpt("Empty screenshot");
5685 return False
5686
5687 # The simple algoritm below assumes that Windows OS desktop consists of a pixels that
5688 # are not too dark or bright but usually of blue tint.
5689 cDesktopPixels = 0
5690 cDesktopPixelsBlue = 0
5691 iThreshold = 20
5692 for i in range(0, cPixels, 4) :
5693 if sys.version_info[0] >= 3:
5694 iRed = aRGBData[i];
5695 iGreen = aRGBData[i + 1];
5696 iBlue = aRGBData[i + 2];
5697 else: # Python 2.7 treats a pixel data returned by takeScreenShotToArray as a string
5698 iRed = ord(aRGBData[i])
5699 iGreen = ord(aRGBData[i + 1])
5700 iBlue = ord(aRGBData[i + 2])
5701
5702 iBright = (3 * iRed + 6 * iGreen + iBlue) / 10
5703 if iThreshold < iBright < 255 - iThreshold :
5704 cDesktopPixels += 1;
5705 cDesktopPixelsBlue += int(iBlue > iRed and iBlue > iGreen);
5706
5707 fpRatioDesktop = float(cDesktopPixels) / float(cPixels);
5708 reporter.log2('Ratio of not too dark or bright pixels %.2f' % (fpRatioDesktop));
5709
5710 if fpRatioDesktop > 0.1:
5711 fpRatioBlue = float(cDesktopPixelsBlue) / float(cDesktopPixels);
5712 reporter.log2('Ratio of blue pixels %.2f ' % (fpRatioBlue));
5713 if fpRatioBlue > 0.5:
5714 return True
5715
5716 return True # Always return True until the parameters will be calibrated.
5717
5718 def testGuestCtrl3D(self, oSession, oTxsSession, oTestVm): # pylint: disable=unused-argument
5719 """
5720 Tests for VMSVGA device.
5721 """
5722
5723 if oTestVm.sKind not in ('Windows8_64', 'Windows10', 'Windows10_64', 'Windows11_64'):
5724 return (True, oTxsSession);
5725
5726 iScreenId = 0 # TBD: Use a loop to iterate and check all virtual displays
5727 try:
5728 if self.oTstDrv.fpApiVer >= 5.0:
5729 iWidth, iHeight, _, _, _, _ = oSession.o.console.display.getScreenResolution(iScreenId);
5730 else:
5731 iWidth, iHeight, _, _, _ = oSession.o.console.display.getScreenResolution(iScreenId);
5732
5733 aRGBData = oSession.o.console.display.takeScreenShotToArray(iScreenId, iWidth, iHeight,
5734 vboxcon.BitmapFormat_RGBA);
5735 except:
5736 reporter.logXcpt("Unable to take screenshot");
5737 return False
5738
5739 reporter.log2('Got screenshot (%s x %s) having %s bytes' % (iWidth, iHeight, len(aRGBData)));
5740 # @todo r=aeichner Where is this result incorporated in the test result?
5741 # It gets overwritten afterwards without being taken into account
5742 fRc = self.checkScreenShot(iWidth, iHeight, aRGBData);
5743
5744 fRc = fRc and self.oTstDrv.txsRunTest(oTxsSession, 'Checking DX11 feature level', 30 * 1000,
5745 '${CDROM}/${OS/ARCH}/ntDisplay${EXESUFF}', ('ntDisplay', ));
5746 fRc = True; # TBD: Fix for Unattended tests when the ValidationKit.iso is mounted as drive D:
5747 return (fRc, oTxsSession);
5748
5749class tdAddGuestCtrl(vbox.TestDriver): # pylint: disable=too-many-instance-attributes,too-many-public-methods
5750 """
5751 Guest control using VBoxService on the guest.
5752 """
5753
5754 def __init__(self):
5755 vbox.TestDriver.__init__(self);
5756 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
5757 self.asRsrcs = None;
5758 self.fQuick = False; # Don't skip lengthly tests by default.
5759 self.addSubTestDriver(SubTstDrvAddGuestCtrl(self));
5760
5761 #
5762 # Overridden methods.
5763 #
5764 def showUsage(self):
5765 """
5766 Shows the testdriver usage.
5767 """
5768 rc = vbox.TestDriver.showUsage(self);
5769 reporter.log('');
5770 reporter.log('tdAddGuestCtrl Options:');
5771 reporter.log(' --quick');
5772 reporter.log(' Same as --virt-modes hwvirt --cpu-counts 1.');
5773 return rc;
5774
5775 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
5776 """
5777 Parses the testdriver arguments from the command line.
5778 """
5779 if asArgs[iArg] == '--quick':
5780 self.parseOption(['--virt-modes', 'hwvirt'], 0);
5781 self.parseOption(['--cpu-counts', '1'], 0);
5782 self.fQuick = True;
5783 else:
5784 return vbox.TestDriver.parseOption(self, asArgs, iArg);
5785 return iArg + 1;
5786
5787 def actionConfig(self):
5788 if not self.importVBoxApi(): # So we can use the constant below.
5789 return False;
5790
5791 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT;
5792 sGaIso = self.getGuestAdditionsIso();
5793 return self.oTestVmSet.actionConfig(self, eNic0AttachType = eNic0AttachType, sDvdImage = sGaIso);
5794
5795 def actionExecute(self):
5796 return self.oTestVmSet.actionExecute(self, self.testOneCfg);
5797
5798 #
5799 # Test execution helpers.
5800 #
5801 def testOneCfg(self, oVM, oTestVm): # pylint: disable=too-many-statements
5802 """
5803 Runs the specified VM thru the tests.
5804
5805 Returns a success indicator on the general test execution. This is not
5806 the actual test result.
5807 """
5808
5809 self.logVmInfo(oVM);
5810
5811 fRc = True;
5812 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName, fCdWait = False);
5813 reporter.log("TxsSession: %s" % (oTxsSession,));
5814 if oSession is not None:
5815 fRc, oTxsSession = self.aoSubTstDrvs[0].testIt(oTestVm, oSession, oTxsSession);
5816 self.terminateVmBySession(oSession);
5817 else:
5818 fRc = False;
5819 return fRc;
5820
5821 def onExit(self, iRc):
5822 return vbox.TestDriver.onExit(self, iRc);
5823
5824 def gctrlReportError(self, progress):
5825 """
5826 Helper function to report an error of a
5827 given progress object.
5828 """
5829 if progress is None:
5830 reporter.log('No progress object to print error for');
5831 else:
5832 errInfo = progress.errorInfo;
5833 if errInfo:
5834 reporter.log('%s' % (errInfo.text,));
5835 return False;
5836
5837 def gctrlGetRemainingTime(self, msTimeout, msStart):
5838 """
5839 Helper function to return the remaining time (in ms)
5840 based from a timeout value and the start time (both in ms).
5841 """
5842 if msTimeout == 0:
5843 return 0xFFFFFFFE; # Wait forever.
5844 msElapsed = base.timestampMilli() - msStart;
5845 if msElapsed > msTimeout:
5846 return 0; # No time left.
5847 return msTimeout - msElapsed;
5848
5849 def testGuestCtrlManual(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements,unused-argument,unused-variable
5850 """
5851 For manually testing certain bits.
5852 """
5853
5854 reporter.log('Manual testing ...');
5855 fRc = True;
5856
5857 sUser = 'Administrator';
5858 sPassword = 'password';
5859
5860 oGuest = oSession.o.console.guest;
5861 oGuestSession = oGuest.createSession(sUser,
5862 sPassword,
5863 "", "Manual Test");
5864
5865 aWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
5866 _ = oGuestSession.waitForArray(aWaitFor, 30 * 1000);
5867
5868 #sCmd = self.getGuestSystemShell(oTestVm);
5869 #asArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
5870 #aEnv = [];
5871 #afFlags = [];
5872
5873 # Fix this once being used (again).
5874 #for _ in xrange(100):
5875 # oProc = self.processCreateWrapper(oGuestSession, sCmd, asArgs if self.fpApiVer >= 5.0 else asArgs[1:],
5876 # "", # Working directory.
5877 # aEnv, afFlags, 30 * 1000);
5878 #
5879 # aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
5880 # _ = oProc.waitForArray(aWaitFor, 30 * 1000);
5881
5882 oGuestSession.close();
5883 oGuestSession = None;
5884
5885 time.sleep(5);
5886
5887 oSession.o.console.PowerDown();
5888
5889 return (fRc, oTxsSession);
5890
5891if __name__ == '__main__':
5892 sys.exit(tdAddGuestCtrl().main(sys.argv));
Note: See TracBrowser for help on using the repository browser.

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