VirtualBox

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

Last change on this file since 107342 was 107342, checked in by vboxsync, 7 weeks ago

ValidationKit/tests/additions/tdAddGuestCtrl.py: Fixed quoting issue from r166171.

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