VirtualBox

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

Last change on this file since 103068 was 102953, checked in by vboxsync, 12 months ago

fix win64dep, win64dep2, pylint complains. Added fedora39 to uinstall

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 283.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# pylint: disable=too-many-lines
4
5"""
6VirtualBox Validation Kit - Guest Control Tests.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2023 Oracle and/or its affiliates.
12
13This file is part of VirtualBox base platform packages, as
14available from https://www.virtualbox.org.
15
16This program is free software; you can redistribute it and/or
17modify it under the terms of the GNU General Public License
18as published by the Free Software Foundation, in version 3 of the
19License.
20
21This program is distributed in the hope that it will be useful, but
22WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with this program; if not, see <https://www.gnu.org/licenses>.
28
29The contents of this file may alternatively be used under the terms
30of the Common Development and Distribution License Version 1.0
31(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
32in the VirtualBox distribution, in which case the provisions of the
33CDDL are applicable instead of those of the GPL.
34
35You may elect to license modified versions of this file under the
36terms and conditions of either the GPL or the CDDL or both.
37
38SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
39"""
40__version__ = "$Revision: 102953 $"
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 self.asTests = self.asTestsDef;
1429 self.fSkipKnownBugs = False;
1430 self.oTestFiles = None # type: vboxtestfileset.TestFileSet
1431 self.oDebug = tdDebugSettings();
1432 self.sPathVBoxServiceExeGst = '';
1433 self.tpAdditionsVer = ();
1434
1435 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
1436 if asArgs[iArg] == '--add-guest-ctrl-tests':
1437 iArg += 1;
1438 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1439 if asArgs[iArg] == 'all': # Nice for debugging scripts.
1440 self.asTests = self.asTestsDef;
1441 else:
1442 self.asTests = asArgs[iArg].split(':');
1443 for s in self.asTests:
1444 if s not in self.asTestsDef:
1445 raise base.InvalidOption('The "--add-guest-ctrl-tests" value "%s" is not valid; valid values are: %s'
1446 % (s, ' '.join(self.asTestsDef)));
1447 return iNext;
1448 if asArgs[iArg] == '--add-guest-ctrl-skip-known-bugs':
1449 self.fSkipKnownBugs = True;
1450 return iArg + 1;
1451 if asArgs[iArg] == '--no-add-guest-ctrl-skip-known-bugs':
1452 self.fSkipKnownBugs = False;
1453 return iArg + 1;
1454 if asArgs[iArg] == '--add-guest-ctrl-debug-img':
1455 iArg += 1;
1456 iNext = self.oTstDrv.requireMoreArgs(1, asArgs, iArg);
1457 self.oDebug.sVBoxServiceExeHst = asArgs[iArg];
1458 return iNext;
1459 return iArg;
1460
1461 def showUsage(self):
1462 base.SubTestDriverBase.showUsage(self);
1463 reporter.log(' --add-guest-ctrl-tests <s1[:s2[:]]>');
1464 reporter.log(' Default: %s (all)' % (':'.join(self.asTestsDef)));
1465 reporter.log(' --add-guest-ctrl-skip-known-bugs');
1466 reporter.log(' Skips known bugs. Default: --no-add-guest-ctrl-skip-known-bugs');
1467 reporter.log('Debugging:');
1468 reporter.log(' --add-guest-ctrl-debug-img');
1469 reporter.log(' Sets VBoxService image to deploy for debugging');
1470 return True;
1471
1472 def testIt(self, oTestVm, oSession, oTxsSession):
1473 """
1474 Executes the test.
1475
1476 Returns fRc, oTxsSession. The latter may have changed.
1477 """
1478
1479 self.sPathVBoxServiceExeGst = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm), 'VBoxService') \
1480 + base.exeSuff();
1481
1482 # For some tests we need know the Guest Additions version, so fetch it now.
1483 self.tpAdditionsVer = self.oTstDrv.getGuestAdditionsVersion(oSession);
1484
1485 reporter.log("Active tests: %s" % (self.asTests,));
1486
1487 # The tests. Must-succeed tests should be first.
1488 atTests = [
1489 ( True, self.prepareGuestForDebugging, None, 'Manual Debugging',),
1490 ( True, self.prepareGuestForTesting, None, 'Preparations',),
1491 ( True, self.testGuestCtrlSession, 'session_basic', 'Session Basics',),
1492 ( True, self.testGuestCtrlExec, 'exec_basic', 'Execution',),
1493 ( False, self.testGuestCtrlExecTimeout, 'exec_timeout', 'Execution Timeouts',),
1494 ( False, self.testGuestCtrlSessionEnvironment, 'session_env', 'Session Environment',),
1495 ( False, self.testGuestCtrlSessionFileRefs, 'session_file_ref', 'Session File References',),
1496 #( False, self.testGuestCtrlSessionDirRefs, 'session_dir_ref', 'Session Directory References',),
1497 ( False, self.testGuestCtrlSessionProcRefs, 'session_proc_ref', 'Session Process References',),
1498 ( False, self.testGuestCtrlDirCreate, 'dir_create', 'Creating directories',),
1499 ( False, self.testGuestCtrlDirCreateTemp, 'dir_create_temp', 'Creating temporary directories',),
1500 ( False, self.testGuestCtrlDirRead, 'dir_read', 'Reading directories',),
1501 ( False, self.testGuestCtrlCopyTo, 'copy_to', 'Copy to guest',),
1502 ( False, self.testGuestCtrlCopyFrom, 'copy_from', 'Copy from guest',),
1503 ( False, self.testGuestCtrlFileStat, 'file_stat', 'Querying file information (stat)',),
1504 ( False, self.testGuestCtrlFileOpen, 'file_open', 'File open',),
1505 ( False, self.testGuestCtrlFileRead, 'file_read', 'File read',),
1506 ( False, self.testGuestCtrlFileWrite, 'file_write', 'File write',),
1507 ( False, self.testGuestCtrlFileRemove, 'file_remove', 'Removing files',), # Destroys prepped files.
1508 ( False, self.testGuestCtrlUpdateAdditions, 'update_additions', 'Updating Guest Additions',),
1509 # @todo r=aeichner Only enable it again when this really works,
1510 # the 3D tests should probably live in a separate file
1511 # ( False, self.testGuestCtrl3D, '3d', '3D acceleration',),
1512 ];
1513
1514 if not self.fSkipKnownBugs:
1515 atTests.extend([
1516 # @todo Seems to (mainly?) fail on Linux guests, primarily running with systemd as service supervisor.
1517 # Needs to be investigated and fixed.
1518 ( False, self.testGuestCtrlSessionReboot, 'session_reboot', 'Session w/ Guest Reboot',), # May zap /tmp.
1519 ]);
1520
1521 fRc = True;
1522 for fMustSucceed, fnHandler, sShortNm, sTestNm in atTests:
1523
1524 # If for whatever reason the VM object became invalid, bail out.
1525 if not oTestVm:
1526 reporter.error('Test VM object invalid (VBoxSVC or client process crashed?), aborting tests');
1527 fRc = False;
1528 break;
1529
1530 reporter.testStart(sTestNm);
1531 if sShortNm is None or sShortNm in self.asTests:
1532 # Returns (fRc, oTxsSession, oSession) - but only the first one is mandatory.
1533 aoResult = fnHandler(oSession, oTxsSession, oTestVm);
1534 if aoResult is None or isinstance(aoResult, bool):
1535 fRcTest = aoResult;
1536 else:
1537 fRcTest = aoResult[0];
1538 if len(aoResult) > 1:
1539 oTxsSession = aoResult[1];
1540 if len(aoResult) > 2:
1541 oSession = aoResult[2];
1542 assert len(aoResult) == 3;
1543 else:
1544 fRcTest = None;
1545
1546 if fRcTest is False and reporter.testErrorCount() == 0:
1547 fRcTest = reporter.error('Buggy test! Returned False w/o logging the error!');
1548 if reporter.testDone(fRcTest is None)[1] != 0:
1549 fRcTest = False;
1550 fRc = False;
1551
1552 # Stop execution if this is a must-succeed test and it failed.
1553 if fRcTest is False and fMustSucceed is True:
1554 reporter.log('Skipping any remaining tests since the previous one failed.');
1555 break;
1556
1557 # Upload VBoxService logs on failure.
1558 if reporter.testErrorCount() > 0 \
1559 and self.oDebug.sGstVBoxServiceLogPath:
1560 sVBoxServiceLogsTarGz = 'ga-vboxservice-logs-%s.tar.gz' % oTestVm.sVmName;
1561 sGstVBoxServiceLogsTarGz = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), sVBoxServiceLogsTarGz);
1562 if self.oTstDrv.txsPackFile(oSession, oTxsSession, \
1563 sGstVBoxServiceLogsTarGz, self.oDebug.sGstVBoxServiceLogPath, fIgnoreErrors = True):
1564 self.oTstDrv.txsDownloadFiles(oSession, oTxsSession, [ (sGstVBoxServiceLogsTarGz, sVBoxServiceLogsTarGz) ], \
1565 fIgnoreErrors = True);
1566
1567 return (fRc, oTxsSession);
1568
1569 def prepareGuestForDebugging(self, oSession, oTxsSession, oTestVm): # pylint: disable=unused-argument
1570 """
1571 Prepares a guest for (manual) debugging.
1572
1573 This involves copying over and invoking a the locally built VBoxService binary.
1574 """
1575
1576 if self.oDebug.sVBoxServiceExeHst is None: # If no debugging enabled, bail out.
1577 reporter.log('Skipping debugging');
1578 return True;
1579
1580 reporter.log('Preparing for debugging ...');
1581
1582 try:
1583 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1584
1585 self.oTstDrv.sleep(5); # Fudge factor -- wait until the service stopped.
1586
1587 reporter.log('Uploading "%s" to "%s" ...' % (self.oDebug.sVBoxServiceExeHst, self.sPathVBoxServiceExeGst));
1588 oTxsSession.syncUploadFile(self.oDebug.sVBoxServiceExeHst, self.sPathVBoxServiceExeGst);
1589
1590 if oTestVm.isLinux():
1591 oTxsSession.syncChMod(self.sPathVBoxServiceExeGst, 0o755);
1592
1593 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1594
1595 self.oTstDrv.sleep(5); # Fudge factor -- wait until the service is ready.
1596
1597 except:
1598 return reporter.errorXcpt('Unable to prepare for debugging');
1599
1600 return True;
1601
1602 #
1603 # VBoxService handling.
1604 #
1605 def vboxServiceControl(self, oTxsSession, oTestVm, fStart):
1606 """
1607 Controls VBoxService on the guest by starting or stopping the service.
1608 Returns success indicator.
1609 """
1610
1611 fRc = True;
1612
1613 if oTestVm.isWindows():
1614 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'sc.exe');
1615 if oTestVm.sKind in ('WindowsNT3x', 'WindowsNT4', 'Windows2000',): # W2K too?
1616 sPathSC = os.path.join(self.oTstDrv.getGuestSystemDir(oTestVm), 'net.exe');
1617 if fStart is True:
1618 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Starting VBoxService', 30 * 1000,
1619 sPathSC, (sPathSC, 'start', 'VBoxService'));
1620 else:
1621 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Stopping VBoxService', 30 * 1000,
1622 sPathSC, (sPathSC, 'stop', 'VBoxService'));
1623 elif oTestVm.isLinux():
1624 sPathService = "/sbin/rcvboxadd-service";
1625 if fStart is True:
1626 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Starting VBoxService', 30 * 1000,
1627 sPathService, (sPathService, 'start'));
1628 else:
1629 fRc = self.oTstDrv.txsRunTest(oTxsSession, 'Stopping VBoxService', 30 * 1000,
1630 sPathService, (sPathService, 'stop'));
1631 else:
1632 reporter.log('Controlling VBoxService not supported for this guest yet');
1633
1634 return fRc;
1635
1636 def waitForGuestFacility(self, oSession, eFacilityType, sDesc,
1637 eFacilityStatus, cMsTimeout = 30 * 1000):
1638 """
1639 Waits for a guest facility to enter a certain status.
1640 By default the "Active" status is being used.
1641
1642 Returns success status.
1643 """
1644
1645 reporter.log('Waiting for Guest Additions facility "%s" to change to status %s (%dms timeout)...'
1646 % (sDesc, str(eFacilityStatus), cMsTimeout));
1647
1648 fRc = False;
1649
1650 eStatusOld = None;
1651 tsStart = base.timestampMilli();
1652 while base.timestampMilli() - tsStart < cMsTimeout:
1653 try:
1654 eStatus, _ = oSession.o.console.guest.getFacilityStatus(eFacilityType);
1655 reporter.log('Current status is %s' % (str(eStatus)));
1656 if eStatusOld is None:
1657 eStatusOld = eStatus;
1658 except:
1659 reporter.errorXcpt('Getting facility status failed');
1660 break;
1661 if eStatus != eStatusOld:
1662 reporter.log('Status changed to %s' % (str(eStatus)));
1663 eStatusOld = eStatus;
1664 if eStatus == eFacilityStatus:
1665 fRc = True;
1666 break;
1667 self.oTstDrv.sleep(5); # Do some busy waiting.
1668
1669 if not fRc:
1670 reporter.error('Waiting for Guest Additions facility "%s" timed out' % (sDesc));
1671 else:
1672 reporter.log('Guest Additions facility "%s" reached requested status %s after %dms'
1673 % (sDesc, str(eFacilityStatus), base.timestampMilli() - tsStart));
1674
1675 return fRc;
1676
1677 #
1678 # Guest test files.
1679 #
1680
1681 def prepareGuestForTesting(self, oSession, oTxsSession, oTestVm):
1682 """
1683 Prepares the VM for testing, uploading a bunch of files and stuff via TXS.
1684 Returns success indicator.
1685 """
1686 _ = oSession;
1687
1688 #
1689 # Make sure the temporary directory exists.
1690 #
1691 for sDir in [self.oTstDrv.getGuestTempDir(oTestVm), ]:
1692 if oTxsSession.syncMkDirPath(sDir, 0o777) is not True:
1693 return reporter.error('Failed to create directory "%s"!' % (sDir,));
1694
1695 # Query the TestExecService (TXS) version first to find out on what we run.
1696 fGotTxsVer = self.oTstDrv.txsVer(oSession, oTxsSession, 30 * 100, fIgnoreErrors = True);
1697
1698 # Whether to enable verbose logging for VBoxService.
1699 fEnableVerboseLogging = False;
1700
1701 # On Windows guests we always can enable verbose logging. NT4 and W2K doesn't have reg.exe nor (at least NT4) sc.exe.
1702 if oTestVm.isWindows() and oTestVm.sKind not in ('WindowsNT4', 'Windows2000',):
1703 fEnableVerboseLogging = True;
1704
1705 # Old TxS versions had a bug which caused an infinite loop when executing stuff containing "$xxx",
1706 # so check if we got the version here first and skip enabling verbose logging nonetheless if needed.
1707 if not fGotTxsVer:
1708 reporter.log('Too old TxS service running')
1709 fEnableVerboseLogging = False;
1710
1711 # Some older Linux test VMs (like tst-rhel5) don't have a pre-configured 'vbox' user.
1712 # So make sure that this user exists and has the appropriate password set. Ignore any errors.
1713 if oTestVm.isLinux():
1714 sCmdUserAdd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr'), 'useradd');
1715 asArgs = [ sCmdUserAdd, '-m', 'vbox' ];
1716 self.oTstDrv.txsRunTest(oTxsSession, sCmdUserAdd, 5 * 60 * 1000, sCmdUserAdd, asArgs,
1717 fCheckSessionStatus = False);
1718 # We must supply the password in an encrypted form using chpasswd (via stdin).
1719 sCmdChPasswd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm, sPathPrefix = '/usr'), 'chpasswd');
1720 asArgs = [ sCmdChPasswd ];
1721 self.oTstDrv.txsRunTestStdIn(oTxsSession, sCmdChPasswd, 5 * 60 * 1000, sCmdChPasswd, asArgs,
1722 sStdIn = 'vbox:password\n', fIgnoreErrors = True);
1723
1724 #
1725 # Enable VBoxService verbose logging.
1726 #
1727 reporter.log('Enabling verbose VBoxService logging: %s' % (fEnableVerboseLogging));
1728 if fEnableVerboseLogging:
1729 self.oDebug.sGstVBoxServiceLogPath = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), "VBoxService");
1730 if oTxsSession.syncMkDirPath(self.oDebug.sGstVBoxServiceLogPath, 0o777) is not True:
1731 return reporter.error('Failed to create directory "%s"!' % (self.oDebug.sGstVBoxServiceLogPath,));
1732 sPathLogFile = oTestVm.pathJoin(self.oDebug.sGstVBoxServiceLogPath, 'VBoxService.log');
1733
1734 reporter.log('VBoxService logs will be stored in "%s"' % (self.oDebug.sGstVBoxServiceLogPath,));
1735
1736 fRestartVBoxService = False;
1737 if oTestVm.isWindows() and oTestVm.sKind not in ('WindowsNT4', 'Windows2000',):
1738 sPathRegExe = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'reg.exe');
1739 sImagePath = '%s -vvvv --logfile %s' % (self.sPathVBoxServiceExeGst, sPathLogFile);
1740 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging (via registry)',
1741 30 * 1000,
1742 sPathRegExe,
1743 (sPathRegExe, 'add',
1744 'HKLM\\SYSTEM\\CurrentControlSet\\Services\\VBoxService',
1745 '/v', 'ImagePath', '/t', 'REG_SZ', '/d', sImagePath, '/f'));
1746 elif oTestVm.isLinux():
1747 sPathSed = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'sed');
1748 fRestartVBoxService = self.oTstDrv.txsRunTest(oTxsSession, 'Enabling VBoxService verbose logging', 30 * 1000,
1749 sPathSed,
1750 (sPathSed, '-i', '-e', 's/'
1751 '\\$2 \\$3'
1752 '/'
1753 '\\$2 \\$3 -vvvv --logfile \\/var\\/tmp\\/VBoxService\\/VBoxService.log'
1754 '/g',
1755 '/sbin/rcvboxadd-service'));
1756 else:
1757 reporter.log('Verbose logging for VBoxService not supported for this guest yet');
1758
1759 if fRestartVBoxService:
1760 self.vboxServiceControl(oTxsSession, oTestVm, fStart = False);
1761 self.oTstDrv.sleep(5);
1762 self.vboxServiceControl(oTxsSession, oTestVm, fStart = True);
1763 else:
1764 reporter.testStart('Waiting for VBoxService to get started');
1765 fRc = self.waitForGuestFacility(oSession, vboxcon.AdditionsFacilityType_VBoxService, "VBoxService",
1766 vboxcon.AdditionsFacilityStatus_Active);
1767 reporter.testDone();
1768 if not fRc:
1769 return False;
1770
1771 #
1772 # Generate and upload some random files and dirs to the guest.
1773 # Note! Make sure we don't run into too-long-path issues when using
1774 # the test files on the host if.
1775 #
1776 cchGst = len(self.oTstDrv.getGuestTempDir(oTestVm)) + 1 + len('addgst-1') + 1;
1777 cchHst = len(self.oTstDrv.sScratchPath) + 1 + len('copyto/addgst-1') + 1;
1778 cchMaxPath = 230;
1779 if cchHst > cchGst:
1780 cchMaxPath -= cchHst - cchGst;
1781 reporter.log('cchMaxPath=%s (cchHst=%s, cchGst=%s)' % (cchMaxPath, cchHst, cchGst,));
1782 self.oTestFiles = vboxtestfileset.TestFileSet(oTestVm,
1783 self.oTstDrv.getGuestTempDir(oTestVm), 'addgst-1',
1784 # Make sure that we use a lowest common denominator across all supported
1785 # platforms, to make testing the randomly generated file paths work
1786 # reliably.
1787 cchMaxPath = cchMaxPath, asCompatibleWith = [ ('cross') ]);
1788 return self.oTestFiles.upload(oTxsSession, self.oTstDrv);
1789
1790
1791 #
1792 # gctrlXxxx stuff.
1793 #
1794
1795 def gctrlCopyFileFrom(self, oGuestSession, oTest, fExpected):
1796 """
1797 Helper function to copy a single file from the guest to the host.
1798 """
1799
1800 # As we pass-in randomly generated file names, the source sometimes can be empty, which
1801 # in turn will result in a (correct) error by the API. Simply skip this function then.
1802 if not oTest.sSrc:
1803 reporter.log2('Skipping guest file "%s"' % (limitString(oTest.sSrc)));
1804 return fExpected;
1805
1806 #
1807 # Do the copying.
1808 #
1809 reporter.log2('Copying guest file "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1810 try:
1811 if self.oTstDrv.fpApiVer >= 5.0:
1812 oCurProgress = oGuestSession.fileCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1813 else:
1814 oCurProgress = oGuestSession.copyFrom(oTest.sSrc, oTest.sDst, oTest.afFlags);
1815 except:
1816 reporter.maybeErrXcpt(fExpected, 'Copy from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1817 return False;
1818 if oCurProgress is None:
1819 return reporter.error('No progress object returned');
1820 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlFileCopyFrom");
1821 oProgress.wait();
1822 if not oProgress.isSuccess():
1823 oProgress.logResult(fIgnoreErrors = not fExpected);
1824 return False;
1825
1826 #
1827 # Check the result if we can.
1828 #
1829 if oTest.oSrc:
1830 assert isinstance(oTest.oSrc, testfileset.TestFile);
1831 sDst = oTest.sDst;
1832 if os.path.isdir(sDst):
1833 sDst = os.path.join(sDst, oTest.oSrc.sName);
1834 try:
1835 oFile = open(sDst, 'rb'); # pylint: disable=consider-using-with
1836 except:
1837 # Don't report expected non-existing paths / files as an error.
1838 return reporter.maybeErrXcpt(fExpected, 'open(%s) failed during verfication (file / path not found)' % (sDst,));
1839 fEqual = oTest.oSrc.equalFile(oFile);
1840 oFile.close();
1841 if not fEqual:
1842 return reporter.error('Content differs for "%s"' % (sDst,));
1843
1844 return True;
1845
1846 def __compareTestDir(self, oDir, sHostPath): # type: (testfileset.TestDir, str) -> bool
1847 """
1848 Recursively compare the content of oDir and sHostPath.
1849
1850 Returns True on success, False + error logging on failure.
1851
1852 Note! This ASSUMES that nothing else was copied to sHostPath!
1853 """
1854 #
1855 # First check out all the entries and files in the directory.
1856 #
1857 dLeftUpper = dict(oDir.dChildrenUpper);
1858 try:
1859 asEntries = os.listdir(sHostPath);
1860 except:
1861 return reporter.errorXcpt('os.listdir(%s) failed' % (sHostPath,));
1862
1863 fRc = True;
1864 for sEntry in asEntries:
1865 sEntryUpper = sEntry.upper();
1866 if sEntryUpper not in dLeftUpper:
1867 fRc = reporter.error('Unexpected entry "%s" in "%s"' % (sEntry, sHostPath,));
1868 else:
1869 oFsObj = dLeftUpper[sEntryUpper];
1870 del dLeftUpper[sEntryUpper];
1871
1872 if isinstance(oFsObj, testfileset.TestFile):
1873 sFilePath = os.path.join(sHostPath, oFsObj.sName);
1874 try:
1875 oFile = open(sFilePath, 'rb'); # pylint: disable=consider-using-with
1876 except:
1877 fRc = reporter.errorXcpt('open(%s) failed during verfication' % (sFilePath,));
1878 else:
1879 fEqual = oFsObj.equalFile(oFile);
1880 oFile.close();
1881 if not fEqual:
1882 fRc = reporter.error('Content differs for "%s"' % (sFilePath,));
1883
1884 # List missing entries:
1885 for sKey in dLeftUpper:
1886 oEntry = dLeftUpper[sKey];
1887 fRc = reporter.error('%s: Missing %s "%s" (src path: %s)'
1888 % (sHostPath, oEntry.sName,
1889 'file' if isinstance(oEntry, testfileset.TestFile) else 'directory', oEntry.sPath));
1890
1891 #
1892 # Recurse into subdirectories.
1893 #
1894 for oFsObj in oDir.aoChildren:
1895 if isinstance(oFsObj, testfileset.TestDir):
1896 fRc = self.__compareTestDir(oFsObj, os.path.join(sHostPath, oFsObj.sName)) and fRc;
1897 return fRc;
1898
1899 def gctrlCopyDirFrom(self, oGuestSession, oTest, fExpected):
1900 """
1901 Helper function to copy a directory from the guest to the host.
1902 """
1903
1904 # As we pass-in randomly generated directories, the source sometimes can be empty, which
1905 # in turn will result in a (correct) error by the API. Simply skip this function then.
1906 if not oTest.sSrc:
1907 reporter.log2('Skipping guest dir "%s"' % (limitString(oTest.sSrc)));
1908 return fExpected;
1909
1910 #
1911 # Do the copying.
1912 #
1913 reporter.log2('Copying guest dir "%s" to host "%s"' % (limitString(oTest.sSrc), limitString(oTest.sDst)));
1914 try:
1915 if self.oTstDrv.fpApiVer >= 7.0:
1916 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
1917 if not oTest.afFlags:
1918 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
1919 elif vboxcon.DirectoryCopyFlag_Recursive not in oTest.afFlags:
1920 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
1921 ## @todo Ditto.
1922 if not oTest.afFlags:
1923 oTest.afFlags = [ vboxcon.DirectoryCopyFlag_FollowLinks, ];
1924 elif vboxcon.DirectoryCopyFlag_FollowLinks not in oTest.afFlags:
1925 oTest.afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
1926 oCurProgress = oGuestSession.directoryCopyFromGuest(oTest.sSrc, oTest.sDst, oTest.afFlags);
1927 except:
1928 reporter.maybeErrXcpt(fExpected, 'Copy dir from exception for sSrc="%s", sDst="%s":' % (oTest.sSrc, oTest.sDst,));
1929 return False;
1930 if oCurProgress is None:
1931 return reporter.error('No progress object returned');
1932
1933 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlDirCopyFrom");
1934 oProgress.wait();
1935 if not oProgress.isSuccess():
1936 oProgress.logResult(fIgnoreErrors = not fExpected);
1937 return False;
1938
1939 #
1940 # Check the result if we can.
1941 #
1942 if oTest.oSrc:
1943 assert isinstance(oTest.oSrc, testfileset.TestDir);
1944 sDst = oTest.sDst;
1945 if oTest.fIntoDst:
1946 return self.__compareTestDir(oTest.oSrc, os.path.join(sDst, oTest.oSrc.sName));
1947 oDummy = testfileset.TestDir(None, 'dummy');
1948 oDummy.aoChildren = [oTest.oSrc,]
1949 oDummy.dChildrenUpper = { oTest.oSrc.sName.upper(): oTest.oSrc, };
1950 return self.__compareTestDir(oDummy, sDst);
1951 return True;
1952
1953 def gctrlCopyFileTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1954 """
1955 Helper function to copy a single file from the host to the guest.
1956
1957 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
1958 """
1959 reporter.log2('Copying host file "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
1960 try:
1961 if self.oTstDrv.fpApiVer >= 5.0:
1962 oCurProgress = oGuestSession.fileCopyToGuest(sSrc, sDst, afFlags);
1963 else:
1964 oCurProgress = oGuestSession.copyTo(sSrc, sDst, afFlags);
1965 except:
1966 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
1967 return False;
1968
1969 if oCurProgress is None:
1970 return reporter.error('No progress object returned');
1971 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
1972
1973 try:
1974 oProgress.wait();
1975 if not oProgress.isSuccess():
1976 oProgress.logResult(fIgnoreErrors = not fIsError);
1977 return False;
1978 except:
1979 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
1980 return False;
1981 return True;
1982
1983 def gctrlCopyDirTo(self, oGuestSession, sSrc, sDst, afFlags, fIsError):
1984 """
1985 Helper function to copy a directory (tree) from the host to the guest.
1986
1987 afFlags is either None or an array of vboxcon.DirectoryCopyFlag_Xxxx values.
1988 """
1989 reporter.log2('Copying host directory "%s" to guest "%s" (flags %s)' % (limitString(sSrc), limitString(sDst), afFlags));
1990 try:
1991 if self.oTstDrv.fpApiVer >= 7.0:
1992 ## @todo Make the following new flags implicit for 7.0 for now. Develop dedicated tests for this later and remove.
1993 if not afFlags:
1994 afFlags = [ vboxcon.DirectoryCopyFlag_Recursive, ];
1995 elif vboxcon.DirectoryCopyFlag_Recursive not in afFlags:
1996 afFlags.append(vboxcon.DirectoryCopyFlag_Recursive);
1997 ## @todo Ditto.
1998 if not afFlags:
1999 afFlags = [vboxcon.DirectoryCopyFlag_FollowLinks,];
2000 elif vboxcon.DirectoryCopyFlag_FollowLinks not in afFlags:
2001 afFlags.append(vboxcon.DirectoryCopyFlag_FollowLinks);
2002 oCurProgress = oGuestSession.directoryCopyToGuest(sSrc, sDst, afFlags);
2003 except:
2004 reporter.maybeErrXcpt(fIsError, 'sSrc=%s sDst=%s' % (sSrc, sDst,));
2005 return False;
2006
2007 if oCurProgress is None:
2008 return reporter.error('No progress object returned');
2009 oProgress = vboxwrappers.ProgressWrapper(oCurProgress, self.oTstDrv.oVBoxMgr, self.oTstDrv, "gctrlCopyFileTo");
2010
2011 try:
2012 oProgress.wait();
2013 if not oProgress.isSuccess():
2014 oProgress.logResult(fIgnoreErrors = not fIsError);
2015 return False;
2016 except:
2017 reporter.maybeErrXcpt(fIsError, 'Wait exception for sSrc="%s", sDst="%s":' % (sSrc, sDst));
2018 return False;
2019 return True;
2020
2021 def gctrlCreateDir(self, oTest, oRes, oGuestSession):
2022 """
2023 Helper function to create a guest directory specified in the current test.
2024 """
2025 reporter.log2('Creating directory "%s"' % (limitString(oTest.sDirectory),));
2026 try:
2027 oGuestSession.directoryCreate(oTest.sDirectory, oTest.fMode, oTest.afFlags);
2028 except:
2029 reporter.maybeErrXcpt(oRes.fRc, 'Failed to create "%s" fMode=%o afFlags=%s'
2030 % (oTest.sDirectory, oTest.fMode, oTest.afFlags,));
2031 return not oRes.fRc;
2032 if oRes.fRc is not True:
2033 return reporter.error('Did not expect to create directory "%s"!' % (oTest.sDirectory,));
2034
2035 # Check if the directory now exists.
2036 try:
2037 if self.oTstDrv.fpApiVer >= 5.0:
2038 fDirExists = oGuestSession.directoryExists(oTest.sDirectory, False);
2039 else:
2040 fDirExists = oGuestSession.directoryExists(oTest.sDirectory);
2041 except:
2042 return reporter.errorXcpt('directoryExists failed on "%s"!' % (oTest.sDirectory,));
2043 if not fDirExists:
2044 return reporter.errorXcpt('directoryExists returned False on "%s" after directoryCreate succeeded!'
2045 % (oTest.sDirectory,));
2046 return True;
2047
2048 def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, fUseDirList = False, cEntriesPerRead = 0, sSubDir = None):
2049 """
2050 Helper function to recursively read a guest directory tree specified in the current test.
2051 """
2052 sDir = oTest.sDirectory;
2053 sFilter = oTest.sFilter;
2054 afFlags = oTest.afFlags;
2055 oTestVm = oTest.oCreds.oTestVm;
2056 sCurDir = oTestVm.pathJoin(sDir, sSubDir) if sSubDir else sDir;
2057
2058 fRc = True; # Be optimistic.
2059 cDirs = 0; # Number of directories read.
2060 cFiles = 0; # Number of files read.
2061 cOthers = 0; # Other files.
2062
2063 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2064 aFsObjInfo = [];
2065
2066 # Open the directory:
2067 reporter.log2('Directory="%s", filter="%s", afFlags="%s", fUseDirList=%s, cEntriesPerRead=%d'
2068 % (limitString(sCurDir), sFilter, afFlags, fUseDirList, cEntriesPerRead));
2069 try:
2070 oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
2071 except:
2072 reporter.maybeErrXcpt(fIsError, 'sCurDir=%s sFilter=%s afFlags=%s' % (sCurDir, sFilter, afFlags,))
2073 return (False, 0, 0, 0);
2074
2075 # Read the directory.
2076 fDone = False;
2077 while fRc is True:
2078 reporter.log3('Reading next batch ...');
2079 aFsObjInfo = [];
2080 try:
2081 if not fUseDirList:
2082 aFsObjInfo.append(oCurDir.read());
2083 else:
2084 if not cEntriesToRead:
2085 cEntriesToRead = random.randrange(1, 32768);
2086 aFsObjInfo = oCurDir.list(cEntriesToRead);
2087 except Exception as oXcpt:
2088 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2089 if fUseDirList:
2090 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % (sCurDir, cEntriesToRead));
2091 else:
2092 if self.oTstDrv.fpApiVer > 5.2:
2093 reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
2094 else:
2095 # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
2096 reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
2097 fRc = False;
2098 else:
2099 reporter.log2('\tNo more directory entries for "%s"' % (limitString(sCurDir),));
2100 fDone = True;
2101 break;
2102
2103 if fDone or not fRc: # Abort reading?
2104 break;
2105
2106 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2107 for oFsObjInfo in aFsObjInfo:
2108 try:
2109 sName = oFsObjInfo.name;
2110 eType = oFsObjInfo.type;
2111 except:
2112 fRc = reporter.errorXcpt();
2113 break;
2114
2115 if sName in ('.', '..', ):
2116 if eType != vboxcon.FsObjType_Directory:
2117 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2118 % (sName, eType, vboxcon.FsObjType_Directory));
2119 elif eType == vboxcon.FsObjType_Directory:
2120 reporter.log2(' Directory "%s"' % limitString(oFsObjInfo.name));
2121 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
2122 fUseDirList, cEntriesPerRead,
2123 oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
2124 fRc = aSubResult[0];
2125 cDirs += aSubResult[1] + 1;
2126 cFiles += aSubResult[2];
2127 cOthers += aSubResult[3];
2128 elif eType is vboxcon.FsObjType_File:
2129 reporter.log4(' File "%s"' % oFsObjInfo.name);
2130 cFiles += 1;
2131 elif eType is vboxcon.FsObjType_Symlink:
2132 reporter.log4(' Symlink "%s" -- not tested yet' % oFsObjInfo.name);
2133 cOthers += 1;
2134 elif oTestVm.isWindows() \
2135 or oTestVm.isOS2() \
2136 or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
2137 vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
2138 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
2139 (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
2140 else:
2141 cOthers += 1;
2142
2143 # Close the directory
2144 try:
2145 oCurDir.close();
2146 except:
2147 fRc = reporter.errorXcpt('sCurDir=%s' % (sCurDir));
2148
2149 return (fRc, cDirs, cFiles, cOthers);
2150
2151 def gctrlReadDirTree2(self, oGuestSession, oDir, fUseDirList = False, cEntriesPerRead = 0):
2152 # type: (testfileset.TestDir) -> bool
2153 """
2154 Helper function to recursively read a guest directory tree specified in the current test.
2155 """
2156
2157 #
2158 # Process the directory.
2159 #
2160
2161 # Open the directory:
2162 try:
2163 oCurDir = oGuestSession.directoryOpen(oDir.sPath, '', None);
2164 except:
2165 return reporter.errorXcpt('sPath=%s' % (oDir.sPath,));
2166
2167 # Read the directory.
2168 dLeftUpper = dict(oDir.dChildrenUpper);
2169 cDot = 0;
2170 cDotDot = 0;
2171 fRc = True;
2172 cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
2173 aFsObjInfo = [];
2174 while True:
2175 reporter.log3('Reading next batch ...');
2176 aFsObjInfo = [];
2177 try:
2178 if not fUseDirList:
2179 aFsObjInfo.append(oCurDir.read());
2180 else:
2181 if not cEntriesToRead:
2182 cEntriesToRead = random.randrange(1, 32768);
2183 aFsObjInfo = oCurDir.list(cEntriesToRead);
2184 except Exception as oXcpt:
2185 if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
2186 if fUseDirList:
2187 fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % \
2188 (oDir.sPath, cEntriesToRead));
2189 else:
2190 fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath));
2191 else:
2192 reporter.log2('\tNo more directory entries for "%s"' % (limitString(oDir.sPath),));
2193 break;
2194
2195 reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
2196 for oFsObjInfo in aFsObjInfo:
2197 try:
2198 sName = oFsObjInfo.name;
2199 eType = oFsObjInfo.type;
2200 cbFile = oFsObjInfo.objectSize;
2201 ## @todo check further attributes.
2202 except:
2203 fRc = reporter.errorXcpt();
2204 break;
2205
2206 # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
2207 if sName in ('.', '..', ):
2208 if eType != vboxcon.FsObjType_Directory:
2209 fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
2210 % (sName, eType, vboxcon.FsObjType_Directory));
2211 if sName == '.': cDot += 1;
2212 else: cDotDot += 1;
2213 else:
2214 # Find the child and remove it from the dictionary.
2215 sNameUpper = sName.upper();
2216 oFsObj = dLeftUpper.get(sNameUpper);
2217 if oFsObj is None:
2218 fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
2219 % (sName, oDir.sPath, eType, cbFile,));
2220 else:
2221 del dLeftUpper[sNameUpper];
2222
2223 # Check type
2224 if isinstance(oFsObj, testfileset.TestDir):
2225 if eType != vboxcon.FsObjType_Directory:
2226 fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
2227 % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
2228 elif isinstance(oFsObj, testfileset.TestFile):
2229 if eType != vboxcon.FsObjType_File:
2230 fRc = reporter.error('%s: expected file (%d), got eType=%d!'
2231 % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
2232 else:
2233 fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
2234
2235 # Check the name.
2236 if oFsObj.sName != sName:
2237 fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % \
2238 (oFsObj.sPath, oFsObj.sName, sName,));
2239
2240 # Check the size if a file.
2241 if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
2242 fRc = reporter.error('%s: expected size %s, got %s instead!' % \
2243 (oFsObj.sPath, oFsObj.cbContent, cbFile,));
2244
2245 ## @todo check timestamps and attributes.
2246
2247 # Close the directory
2248 try:
2249 oCurDir.close();
2250 except:
2251 fRc = reporter.errorXcpt('oDir.sPath=%s' % (oDir.sPath,));
2252
2253 # Any files left over?
2254 for sKey in dLeftUpper:
2255 oFsObj = dLeftUpper[sKey];
2256 fRc = reporter.error('%s: Was not returned! (%s)' % (oFsObj.sPath, type(oFsObj),));
2257
2258 # Check the dot and dot-dot counts.
2259 if cDot != 1:
2260 fRc = reporter.error('%s: Found %s "." entries, expected exactly 1!' % (oDir.sPath, cDot,));
2261 if cDotDot != 1:
2262 fRc = reporter.error('%s: Found %s ".." entries, expected exactly 1!' % (oDir.sPath, cDotDot,));
2263
2264 #
2265 # Recurse into subdirectories using info from oDir.
2266 #
2267 for oFsObj in oDir.aoChildren:
2268 if isinstance(oFsObj, testfileset.TestDir):
2269 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj, fUseDirList, cEntriesPerRead) and fRc;
2270
2271 return fRc;
2272
2273 def gctrlExecDoTest(self, i, oTest, oRes, oGuestSession):
2274 """
2275 Wrapper function around gctrlExecute to provide more sanity checking
2276 when needed in actual execution tests.
2277 """
2278 reporter.log('Testing #%d, cmd="%s" ...' % (i, oTest.sCmd));
2279 fRcExec = self.gctrlExecute(oTest, oGuestSession, oRes.fRc);
2280 if fRcExec == oRes.fRc:
2281 fRc = True;
2282 if fRcExec is True:
2283 # Compare exit status / code on successful process execution.
2284 if oTest.uExitStatus != oRes.uExitStatus \
2285 or oTest.iExitCode != oRes.iExitCode:
2286 fRc = reporter.error('Test #%d (%s) failed: Got exit status + code %d,%d, expected %d,%d'
2287 % (i, oTest.asArgs, oTest.uExitStatus, oTest.iExitCode,
2288 oRes.uExitStatus, oRes.iExitCode));
2289
2290 # Compare test / result buffers on successful process execution.
2291 if oTest.sBuf is not None and oRes.sBuf is not None:
2292 if not utils.areBytesEqual(oTest.sBuf, oRes.sBuf):
2293 fRc = reporter.error('Test #%d (%s) failed: Got buffer\n%s (%d bytes), expected\n%s (%d bytes)'
2294 % (i, oTest.asArgs,
2295 map(hex, map(ord, oTest.sBuf)), len(oTest.sBuf),
2296 map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf)));
2297 reporter.log2('Test #%d passed: Buffers match (%d bytes)' % (i, len(oRes.sBuf)));
2298 elif oRes.sBuf and not oTest.sBuf:
2299 fRc = reporter.error('Test #%d (%s) failed: Got no buffer data, expected\n%s (%dbytes)' %
2300 (i, oTest.asArgs, map(hex, map(ord, oRes.sBuf)), len(oRes.sBuf),));
2301
2302 if oRes.cbStdOut is not None and oRes.cbStdOut != oTest.cbStdOut:
2303 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stdout data, expected %d'
2304 % (i, oTest.asArgs, oTest.cbStdOut, oRes.cbStdOut));
2305 if oRes.cbStdErr is not None and oRes.cbStdErr != oTest.cbStdErr:
2306 fRc = reporter.error('Test #%d (%s) failed: Got %d bytes of stderr data, expected %d'
2307 % (i, oTest.asArgs, oTest.cbStdErr, oRes.cbStdErr));
2308 else:
2309 fRc = reporter.error('Test #%d (%s) failed: Got %s, expected %s' % (i, oTest.asArgs, fRcExec, oRes.fRc));
2310 return fRc;
2311
2312 def processCreateWrapper(self, oGuestSession, sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS):
2313 """
2314 Wrapepr function to deal with different flavors of the IGuestProcess::processCreate call,
2315 depending on the API version.
2316
2317 Returns oProcess object on success, None on failure.
2318 """
2319 oProcess = None;
2320
2321 reporter.log2('Executing sCmd=%s, cCwd=%s, afFlags=%s, timeoutMS=%d, asArgs=%s, asEnv=%s'
2322 % (sCmd, sCwd, afFlags, timeoutMS, limitString(asArgs), limitString(aEnv),));
2323
2324 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485:
2325 # 7.1 adds a current working directory parameter.
2326 oProcess = oGuestSession.processCreate(sCmd, asArgs, sCwd, aEnv, afFlags, timeoutMS);
2327 else:
2328 oProcess = oGuestSession.processCreate(sCmd,
2329 asArgs if self.oTstDrv.fpApiVer >= 5.0 else asArgs[1:],
2330 aEnv, afFlags, timeoutMS);
2331 return oProcess;
2332
2333 def gctrlExecute(self, oTest, oGuestSession, fIsError): # pylint: disable=too-many-statements
2334 """
2335 Helper function to execute a program on a guest, specified in the current test.
2336
2337 Note! This weirdo returns results (process exitcode and status) in oTest.
2338 """
2339 fRc = True; # Be optimistic.
2340
2341 # Reset the weird result stuff:
2342 oTest.cbStdOut = 0;
2343 oTest.cbStdErr = 0;
2344 oTest.sBuf = '';
2345 oTest.uExitStatus = 0;
2346 oTest.iExitCode = 0;
2347
2348 ## @todo Compare execution timeouts!
2349 #tsStart = base.timestampMilli();
2350
2351 try:
2352 reporter.log2('Using session user=%s, sDomain=%s, name=%s, timeout=%d'
2353 % (oGuestSession.user, oGuestSession.domain, oGuestSession.name, oGuestSession.timeout,));
2354 except:
2355 return reporter.errorXcpt();
2356
2357 #
2358 # Start the process:
2359 #
2360
2361 try:
2362 oProcess = self.processCreateWrapper(oGuestSession, oTest.sCmd, oTest.asArgs, oTest.sCwd,
2363 oTest.aEnv, oTest.afFlags, oTest.timeoutMS);
2364 except:
2365 reporter.maybeErrXcpt(fIsError, 'type=%s, asArgs=%s' % (type(oTest.asArgs), oTest.asArgs,));
2366 return False;
2367 if oProcess is None:
2368 return reporter.error('oProcess is None! (%s)' % (oTest.asArgs,));
2369
2370 #time.sleep(5); # try this if you want to see races here.
2371
2372 # Wait for the process to start properly:
2373 reporter.log2('Process start requested, waiting for start (%dms) ...' % (oTest.timeoutMS,));
2374 iPid = -1;
2375 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Start, ];
2376 try:
2377 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2378 except:
2379 reporter.maybeErrXcpt(fIsError, 'waitforArray failed for asArgs=%s' % (oTest.asArgs,));
2380 fRc = False;
2381 else:
2382 try:
2383 eStatus = oProcess.status;
2384 iPid = oProcess.PID;
2385 except:
2386 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2387 else:
2388 reporter.log2('Wait result returned: %d, current process status is: %d' % (eWaitResult, eStatus,));
2389
2390 #
2391 # Wait for the process to run to completion if necessary.
2392 #
2393 # Note! The above eWaitResult return value can be ignored as it will
2394 # (mostly) reflect the process status anyway.
2395 #
2396 if eStatus == vboxcon.ProcessStatus_Started:
2397
2398 # What to wait for:
2399 aeWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate, ];
2400 if vboxcon.ProcessCreateFlag_WaitForStdOut in oTest.afFlags:
2401 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdOut);
2402 if vboxcon.ProcessCreateFlag_WaitForStdErr in oTest.afFlags:
2403 aeWaitFor.append(vboxcon.ProcessWaitForFlag_StdErr);
2404 ## @todo Add vboxcon.ProcessWaitForFlag_StdIn.
2405
2406 reporter.log2('Process (PID %d) started, waiting for termination (%dms), aeWaitFor=%s ...'
2407 % (iPid, oTest.timeoutMS, aeWaitFor));
2408 acbFdOut = [0,0,0];
2409 while True:
2410 try:
2411 eWaitResult = oProcess.waitForArray(aeWaitFor, oTest.timeoutMS);
2412 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2413 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2414 try: oProcess.close();
2415 except: pass;
2416 break;
2417 except:
2418 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2419 break;
2420 #reporter.log2('Wait returned: %d' % (eWaitResult,));
2421
2422 # Process output:
2423 for eFdResult, iFd, sFdNm in [ (vboxcon.ProcessWaitResult_StdOut, 1, 'stdout'),
2424 (vboxcon.ProcessWaitResult_StdErr, 2, 'stderr'), ]:
2425 if eWaitResult in (eFdResult, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2426 try:
2427 abBuf = oProcess.read(iFd, 64 * 1024, oTest.timeoutMS);
2428 except KeyboardInterrupt: # Not sure how helpful this is, but whatever.
2429 reporter.error('Process (PID %d) execution interrupted' % (iPid,));
2430 try: oProcess.close();
2431 except: pass;
2432 except:
2433 reporter.maybeErrXcpt(fIsError, 'asArgs=%s' % (oTest.asArgs,));
2434 else:
2435 if abBuf:
2436 reporter.log2('Process (PID %d) got %d bytes of %s data (type: %s)'
2437 % (iPid, len(abBuf), sFdNm, type(abBuf)));
2438 if reporter.getVerbosity() >= 4:
2439 sBuf = '';
2440 if sys.version_info >= (2, 7):
2441 if isinstance(abBuf, memoryview): ## @todo Why is this happening?
2442 abBuf = abBuf.tobytes();
2443 sBuf = abBuf.decode("utf-8");
2444 if sys.version_info <= (2, 7):
2445 if isinstance(abBuf, buffer): # (for 3.0+) pylint: disable=undefined-variable
2446 sBuf = str(abBuf);
2447 for sLine in sBuf.splitlines():
2448 reporter.log4('%s: %s' % (sFdNm, sLine));
2449 acbFdOut[iFd] += len(abBuf);
2450 oTest.sBuf = abBuf; ## @todo Figure out how to uniform + append!
2451
2452 ## Process input (todo):
2453 #if eWaitResult in (vboxcon.ProcessWaitResult_StdIn, vboxcon.ProcessWaitResult_WaitFlagNotSupported):
2454 # reporter.log2('Process (PID %d) needs stdin data' % (iPid,));
2455
2456 # Termination or error?
2457 if eWaitResult in (vboxcon.ProcessWaitResult_Terminate,
2458 vboxcon.ProcessWaitResult_Error,
2459 vboxcon.ProcessWaitResult_Timeout,):
2460 try: eStatus = oProcess.status;
2461 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2462 reporter.log2('Process (PID %d) reported terminate/error/timeout: %d, status: %d'
2463 % (iPid, eWaitResult, eStatus,));
2464 break;
2465
2466 # End of the wait loop.
2467 _, oTest.cbStdOut, oTest.cbStdErr = acbFdOut;
2468
2469 try: eStatus = oProcess.status;
2470 except: fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2471 reporter.log2('Final process status (PID %d) is: %d' % (iPid, eStatus));
2472 reporter.log2('Process (PID %d) %d stdout, %d stderr' % (iPid, oTest.cbStdOut, oTest.cbStdErr));
2473
2474 #
2475 # Get the final status and exit code of the process.
2476 #
2477 try:
2478 oTest.uExitStatus = oProcess.status;
2479 oTest.iExitCode = oProcess.exitCode;
2480 except:
2481 fRc = reporter.errorXcpt('asArgs=%s' % (oTest.asArgs,));
2482 reporter.log2('Process (PID %d) has exit code: %d; status: %d ' % (iPid, oTest.iExitCode, oTest.uExitStatus));
2483 return fRc;
2484
2485 def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
2486 """
2487 Tests the guest session environment changes.
2488 """
2489 aoTests = [
2490 # Check basic operations.
2491 tdTestSessionEx([ # Initial environment is empty.
2492 tdStepSessionCheckEnv(),
2493 # Check clearing empty env.
2494 tdStepSessionClearEnv(),
2495 tdStepSessionCheckEnv(),
2496 # Check set.
2497 tdStepSessionSetEnv('FOO', 'BAR'),
2498 tdStepSessionCheckEnv(['FOO=BAR',]),
2499 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2500 tdStepSessionClearEnv(),
2501 tdStepSessionCheckEnv(),
2502 # Check unset.
2503 tdStepSessionUnsetEnv('BAR'),
2504 tdStepSessionCheckEnv(['BAR']),
2505 tdStepSessionClearEnv(),
2506 tdStepSessionCheckEnv(),
2507 # Set + unset.
2508 tdStepSessionSetEnv('FOO', 'BAR'),
2509 tdStepSessionCheckEnv(['FOO=BAR',]),
2510 tdStepSessionUnsetEnv('FOO'),
2511 tdStepSessionCheckEnv(['FOO']),
2512 # Bulk environment changes (via attrib) (shall replace existing 'FOO').
2513 tdStepSessionBulkEnv( ['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2514 tdStepSessionCheckEnv(['PATH=/bin:/usr/bin', 'TMPDIR=/var/tmp', 'USER=root']),
2515 ]),
2516 tdTestSessionEx([ # Check that setting the same value several times works.
2517 tdStepSessionSetEnv('FOO','BAR'),
2518 tdStepSessionCheckEnv([ 'FOO=BAR',]),
2519 tdStepSessionSetEnv('FOO','BAR2'),
2520 tdStepSessionCheckEnv([ 'FOO=BAR2',]),
2521 tdStepSessionSetEnv('FOO','BAR3'),
2522 tdStepSessionCheckEnv([ 'FOO=BAR3',]),
2523 tdStepRequireMinimumApiVer(5.0), # 4.3 can't cope with the remainder.
2524 # Add a little unsetting to the mix.
2525 tdStepSessionSetEnv('BAR', 'BEAR'),
2526 tdStepSessionCheckEnv([ 'FOO=BAR3', 'BAR=BEAR',]),
2527 tdStepSessionUnsetEnv('FOO'),
2528 tdStepSessionCheckEnv([ 'FOO', 'BAR=BEAR',]),
2529 tdStepSessionSetEnv('FOO','BAR4'),
2530 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR',]),
2531 # The environment is case sensitive.
2532 tdStepSessionSetEnv('foo','BAR5'),
2533 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo=BAR5']),
2534 tdStepSessionUnsetEnv('foo'),
2535 tdStepSessionCheckEnv([ 'FOO=BAR4', 'BAR=BEAR', 'foo']),
2536 ]),
2537 tdTestSessionEx([ # Bulk settings merges stuff, last entry standing.
2538 tdStepSessionBulkEnv(['FOO=bar', 'foo=bar', 'FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2539 tdStepSessionCheckEnv(['FOO=doofus', 'TMPDIR=/tmp', 'foo=bar2']),
2540 tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2541 tdStepSessionBulkEnv(['2=1+1', 'FOO=doofus2', ]),
2542 tdStepSessionCheckEnv(['2=1+1', 'FOO=doofus2' ]),
2543 ]),
2544 # Invalid variable names.
2545 tdTestSessionEx([
2546 tdStepSessionSetEnv('', 'FOO', vbox.ComError.E_INVALIDARG),
2547 tdStepSessionCheckEnv(),
2548 tdStepRequireMinimumApiVer(5.0), # 4.3 is too relaxed checking input!
2549 tdStepSessionBulkEnv(['', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2550 tdStepSessionCheckEnv(),
2551 tdStepSessionSetEnv('FOO=', 'BAR', vbox.ComError.E_INVALIDARG),
2552 tdStepSessionCheckEnv(),
2553 ]),
2554 # A bit more weird keys/values.
2555 tdTestSessionEx([ tdStepSessionSetEnv('$$$', ''),
2556 tdStepSessionCheckEnv([ '$$$=',]), ]),
2557 tdTestSessionEx([ tdStepSessionSetEnv('$$$', '%%%'),
2558 tdStepSessionCheckEnv([ '$$$=%%%',]),
2559 ]),
2560 tdTestSessionEx([ tdStepRequireMinimumApiVer(5.0), # 4.3 is buggy!
2561 tdStepSessionSetEnv(u'ß$%ß&', ''),
2562 tdStepSessionCheckEnv([ u'ß$%ß&=',]),
2563 ]),
2564 # Misc stuff.
2565 tdTestSessionEx([ tdStepSessionSetEnv('FOO', ''),
2566 tdStepSessionCheckEnv(['FOO=',]),
2567 ]),
2568 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2569 tdStepSessionCheckEnv(['FOO=BAR',])
2570 ],),
2571 tdTestSessionEx([ tdStepSessionSetEnv('FOO', 'BAR'),
2572 tdStepSessionSetEnv('BAR', 'BAZ'),
2573 tdStepSessionCheckEnv([ 'FOO=BAR', 'BAR=BAZ',]),
2574 ]),
2575 ];
2576 # Leading '=' in the name is okay for windows guests in 6.1 and later (for driver letter CWDs).
2577 if (self.oTstDrv.fpApiVer < 6.1 and self.oTstDrv.fpApiVer >= 5.0) or not oTestVm.isWindows():
2578 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=', '===', vbox.ComError.E_INVALIDARG),
2579 tdStepSessionCheckEnv(),
2580 tdStepSessionSetEnv('=FOO', 'BAR', vbox.ComError.E_INVALIDARG),
2581 tdStepSessionCheckEnv(),
2582 tdStepSessionBulkEnv(['=', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2583 tdStepSessionCheckEnv(),
2584 tdStepSessionBulkEnv(['=FOO', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2585 tdStepSessionCheckEnv(),
2586 tdStepSessionBulkEnv(['=D:=D:/tmp', 'foo=bar'], vbox.ComError.E_INVALIDARG),
2587 tdStepSessionCheckEnv(),
2588 tdStepSessionSetEnv('=D:', 'D:/temp', vbox.ComError.E_INVALIDARG),
2589 tdStepSessionCheckEnv(),
2590 ]));
2591 elif self.oTstDrv.fpApiVer >= 6.1 and oTestVm.isWindows():
2592 aoTests.append(tdTestSessionEx([tdStepSessionSetEnv('=D:', 'D:/tmp'),
2593 tdStepSessionCheckEnv(['=D:=D:/tmp',]),
2594 tdStepSessionBulkEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2595 tdStepSessionCheckEnv(['=D:=D:/temp', '=FOO', 'foo=bar']),
2596 tdStepSessionUnsetEnv('=D:'),
2597 tdStepSessionCheckEnv(['=D:', '=FOO', 'foo=bar']),
2598 ]));
2599
2600 return tdTestSessionEx.executeListTestSessions(aoTests, self.oTstDrv, oSession, oTxsSession, oTestVm, 'SessionEnv');
2601
2602 def testGuestCtrlSessionSimple(self, oSession, oTestVm):
2603 """
2604 Tests simple session-based API calls.
2605 """
2606
2607 reporter.log('Testing simple session-based API calls ...');
2608
2609 # Start a valid session.
2610 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2611 try:
2612 oCreds = tdCtxCreds();
2613 oCreds.applyDefaultsIfNotSet(oTestVm);
2614 oGuest = oSession.o.console.guest;
2615 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionSimple");
2616 oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2617 except:
2618 reporter.logXcpt('Starting session for session-based API calls failed');
2619 return False;
2620
2621 fRc = True;
2622
2623 # User home.
2624 if self.oTstDrv.fpApiVer >= 7.0:
2625 reporter.log('Getting user\'s home directory ...');
2626 try:
2627 reporter.log('User home directory: %s' % (oGuestSession.userHome));
2628 except:
2629 fRc = reporter.logXcpt('Getting user home directory failed');
2630
2631 # User documents.
2632 if self.oTstDrv.fpApiVer >= 7.0:
2633 reporter.log('Getting user\'s documents directory ...');
2634 try:
2635 reporter.log('User documents directory: %s' % (oGuestSession.userDocuments));
2636 except:
2637 fRc = reporter.logXcpt('Getting user documents directory failed');
2638
2639 # Mount points. Only available for Guest Additions >= 7.1.
2640 if self.oTstDrv.fpApiVer >= 7.1:
2641 reporter.log('Getting mount points ...');
2642 try:
2643 aMountpoints = oGuestSession.getMountPoints();
2644 reporter.log('Got %ld mount points' % len(aMountpoints))
2645 for mountPoint in aMountpoints:
2646 reporter.log('Mountpoint: %s' % (mountPoint));
2647 except:
2648 fRc = reporter.logXcpt('Getting mount points failed');
2649
2650 # Close the session.
2651 try:
2652 oGuestSession.close();
2653 except:
2654 fRc = reporter.errorXcpt('Closing guest session failed');
2655
2656 return fRc;
2657
2658 def testGuestCtrlSession(self, oSession, oTxsSession, oTestVm):
2659 """
2660 Tests the guest session handling.
2661 """
2662
2663 #
2664 # Tests:
2665 #
2666 atTests = [
2667 # Invalid parameters.
2668 [ tdTestSession(sUser = ''), tdTestResultSession() ],
2669 # User account without a passwort - forbidden.
2670 [ tdTestSession(sPassword = "" ), tdTestResultSession() ],
2671 # Various wrong credentials.
2672 # Note! Only windows cares about sDomain, the other guests ignores it.
2673 # Note! On Guest Additions < 4.3 this always succeeds because these don't
2674 # support creating dedicated sessions. Instead, guest process creation
2675 # then will fail. See note below.
2676 [ tdTestSession(sPassword = 'bar'), tdTestResultSession() ],
2677 [ tdTestSession(sUser = 'foo', sPassword = 'bar'), tdTestResultSession() ],
2678 [ tdTestSession(sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2679 [ tdTestSession(sUser = 'foo', sPassword = 'bar', sDomain = 'boo'), tdTestResultSession() ],
2680 ];
2681 if oTestVm.isWindows(): # domain is ignored elsewhere.
2682 atTests.append([ tdTestSession(sDomain = 'boo'), tdTestResultSession() ]);
2683
2684 # Finally, correct credentials.
2685 atTests.append([ tdTestSession(), tdTestResultSession(fRc = True, cNumSessions = 1) ]);
2686
2687 #
2688 # Run the tests.
2689 #
2690 fRc = True;
2691 for (i, tTest) in enumerate(atTests):
2692 oCurTest = tTest[0] # type: tdTestSession
2693 oCurRes = tTest[1] # type: tdTestResult
2694
2695 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
2696 if not fRc:
2697 break;
2698 reporter.log('Testing #%d, user="%s", sPassword="%s", sDomain="%s" ...'
2699 % (i, oCurTest.oCreds.sUser, oCurTest.oCreds.sPassword, oCurTest.oCreds.sDomain));
2700 sCurGuestSessionName = 'testGuestCtrlSession: Test #%d' % (i,);
2701 fRc2, oCurGuestSession = oCurTest.createSession(sCurGuestSessionName, fIsError = oCurRes.fRc);
2702
2703 # See note about < 4.3 Guest Additions above.
2704 uProtocolVersion = 2;
2705 if oCurGuestSession is not None:
2706 try:
2707 uProtocolVersion = oCurGuestSession.protocolVersion;
2708 except:
2709 fRc = reporter.errorXcpt('Test #%d' % (i,));
2710
2711 if uProtocolVersion >= 2 and fRc2 is not oCurRes.fRc:
2712 fRc = reporter.error('Test #%d failed: Session creation failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc,));
2713
2714 if fRc2 and oCurGuestSession is None:
2715 fRc = reporter.error('Test #%d failed: no session object' % (i,));
2716 fRc2 = False;
2717
2718 if fRc2:
2719 if uProtocolVersion >= 2: # For Guest Additions < 4.3 getSessionCount() always will return 1.
2720 cCurSessions = oCurTest.getSessionCount(self.oTstDrv.oVBoxMgr);
2721 if cCurSessions != oCurRes.cNumSessions:
2722 fRc = reporter.error('Test #%d failed: Session count does not match: Got %d, expected %d'
2723 % (i, cCurSessions, oCurRes.cNumSessions));
2724 try:
2725 sObjName = oCurGuestSession.name;
2726 except:
2727 fRc = reporter.errorXcpt('Test #%d' % (i,));
2728 else:
2729 if sObjName != sCurGuestSessionName:
2730 fRc = reporter.error('Test #%d failed: Session name does not match: Got "%s", expected "%s"'
2731 % (i, sObjName, sCurGuestSessionName));
2732 fRc2 = oCurTest.closeSession();
2733 if fRc2 is False:
2734 fRc = reporter.error('Test #%d failed: Session could not be closed' % (i,));
2735
2736 if fRc is False:
2737 return (False, oTxsSession);
2738
2739 #
2740 # Multiple sessions.
2741 #
2742 cMaxGuestSessions = 31; # Maximum number of concurrent guest session allowed.
2743 # Actually, this is 32, but we don't test session 0.
2744 aoMultiSessions = {};
2745 reporter.log2('Opening multiple guest tsessions at once ...');
2746 for i in xrange(cMaxGuestSessions + 1):
2747 aoMultiSessions[i] = tdTestSession(sSessionName = 'MultiSession #%d' % (i,));
2748 fRc = aoMultiSessions[i].setEnvironment(oSession, oTxsSession, oTestVm);
2749 if not fRc:
2750 break;
2751
2752 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2753 reporter.log2('MultiSession test #%d count is %d' % (i, cCurSessions));
2754 if cCurSessions != i:
2755 return (reporter.error('MultiSession count is %d, expected %d' % (cCurSessions, i)), oTxsSession);
2756 fRc2, _ = aoMultiSessions[i].createSession('MultiSession #%d' % (i,), i < cMaxGuestSessions);
2757 if fRc2 is not True:
2758 if i < cMaxGuestSessions:
2759 return (reporter.error('MultiSession #%d test failed' % (i,)), oTxsSession);
2760 reporter.log('MultiSession #%d exceeded concurrent guest session count, good' % (i,));
2761 break;
2762
2763 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr);
2764 if cCurSessions is not cMaxGuestSessions:
2765 return (reporter.error('Final session count %d, expected %d ' % (cCurSessions, cMaxGuestSessions,)), oTxsSession);
2766
2767 reporter.log2('Closing MultiSessions ...');
2768 for i in xrange(cMaxGuestSessions):
2769 # Close this session:
2770 oClosedGuestSession = aoMultiSessions[i].oGuestSession;
2771 fRc2 = aoMultiSessions[i].closeSession();
2772 cCurSessions = aoMultiSessions[i].getSessionCount(self.oTstDrv.oVBoxMgr)
2773 reporter.log2('MultiSession #%d count is %d' % (i, cCurSessions,));
2774 if fRc2 is False:
2775 fRc = reporter.error('Closing MultiSession #%d failed' % (i,));
2776 elif cCurSessions != cMaxGuestSessions - (i + 1):
2777 fRc = reporter.error('Expected %d session after closing #%d, got %d instead'
2778 % (cMaxGuestSessions - (i + 1), cCurSessions, i,));
2779 assert aoMultiSessions[i].oGuestSession is None or not fRc2;
2780 ## @todo any way to check that the session is closed other than the 'sessions' attribute?
2781
2782 # Try check that none of the remaining sessions got closed.
2783 try:
2784 aoGuestSessions = self.oTstDrv.oVBoxMgr.getArray(atTests[0][0].oGuest, 'sessions');
2785 except:
2786 return (reporter.errorXcpt('i=%d/%d' % (i, cMaxGuestSessions,)), oTxsSession);
2787 if oClosedGuestSession in aoGuestSessions:
2788 fRc = reporter.error('i=%d/%d: %s should not be in %s'
2789 % (i, cMaxGuestSessions, oClosedGuestSession, aoGuestSessions));
2790 if i + 1 < cMaxGuestSessions: # Not sure what xrange(2,2) does...
2791 for j in xrange(i + 1, cMaxGuestSessions):
2792 if aoMultiSessions[j].oGuestSession not in aoGuestSessions:
2793 fRc = reporter.error('i=%d/j=%d/%d: %s should be in %s'
2794 % (i, j, cMaxGuestSessions, aoMultiSessions[j].oGuestSession, aoGuestSessions));
2795 ## @todo any way to check that they work?
2796
2797 ## @todo Test session timeouts.
2798
2799 fRc2 = self.testGuestCtrlSessionSimple(oSession, oTestVm);
2800 if fRc:
2801 fRc = fRc2;
2802
2803 return (fRc, oTxsSession);
2804
2805 def testGuestCtrlSessionFileRefs(self, oSession, oTxsSession, oTestVm):
2806 """
2807 Tests the guest session file reference handling.
2808 """
2809
2810 # Find a file to play around with:
2811 sFile = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
2812
2813 # Use credential defaults.
2814 oCreds = tdCtxCreds();
2815 oCreds.applyDefaultsIfNotSet(oTestVm);
2816
2817 # Number of stale guest files to create.
2818 cStaleFiles = 10;
2819
2820 #
2821 # Start a session.
2822 #
2823 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2824 try:
2825 oGuest = oSession.o.console.guest;
2826 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionFileRefs");
2827 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2828 except:
2829 return (reporter.errorXcpt(), oTxsSession);
2830
2831 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2832 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2833 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2834 reporter.log('Session successfully started');
2835
2836 #
2837 # Open guest files and "forget" them (stale entries).
2838 # For them we don't have any references anymore intentionally.
2839 #
2840 reporter.log2('Opening stale files');
2841 fRc = True;
2842 for i in xrange(0, cStaleFiles):
2843 try:
2844 if self.oTstDrv.fpApiVer >= 5.0:
2845 oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly, vboxcon.FileOpenAction_OpenExisting, 0);
2846 else:
2847 oGuestSession.fileOpen(sFile, "r", "oe", 0);
2848 # Note: Use a timeout in the call above for not letting the stale processes
2849 # hanging around forever. This can happen if the installed Guest Additions
2850 # do not support terminating guest processes.
2851 except:
2852 fRc = reporter.errorXcpt('Opening stale file #%d failed:' % (i,));
2853 break;
2854
2855 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2856 except: fRc = reporter.errorXcpt();
2857 else:
2858 if cFiles != cStaleFiles:
2859 fRc = reporter.error('Got %d stale files, expected %d' % (cFiles, cStaleFiles));
2860
2861 if fRc is True:
2862 #
2863 # Open non-stale files and close them again.
2864 #
2865 reporter.log2('Opening non-stale files');
2866 aoFiles = [];
2867 for i in xrange(0, cStaleFiles):
2868 try:
2869 if self.oTstDrv.fpApiVer >= 5.0:
2870 oCurFile = oGuestSession.fileOpen(sFile, vboxcon.FileAccessMode_ReadOnly,
2871 vboxcon.FileOpenAction_OpenExisting, 0);
2872 else:
2873 oCurFile = oGuestSession.fileOpen(sFile, "r", "oe", 0);
2874 aoFiles.append(oCurFile);
2875 except:
2876 fRc = reporter.errorXcpt('Opening non-stale file #%d failed:' % (i,));
2877 break;
2878
2879 # Check the count.
2880 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2881 except: fRc = reporter.errorXcpt();
2882 else:
2883 if cFiles != cStaleFiles * 2:
2884 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles * 2));
2885
2886 # Close them.
2887 reporter.log2('Closing all non-stale files again ...');
2888 for i, oFile in enumerate(aoFiles):
2889 try:
2890 oFile.close();
2891 except:
2892 fRc = reporter.errorXcpt('Closing non-stale file #%d failed:' % (i,));
2893
2894 # Check the count again.
2895 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2896 except: fRc = reporter.errorXcpt();
2897 # Here we count the stale files (that is, files we don't have a reference
2898 # anymore for) and the opened and then closed non-stale files (that we still keep
2899 # a reference in aoFiles[] for).
2900 if cFiles != cStaleFiles:
2901 fRc = reporter.error('Got %d total files, expected %d' % (cFiles, cStaleFiles));
2902
2903 #
2904 # Check that all (referenced) non-stale files are now in the "closed" state.
2905 #
2906 reporter.log2('Checking statuses of all non-stale files ...');
2907 for i, oFile in enumerate(aoFiles):
2908 try:
2909 eFileStatus = aoFiles[i].status;
2910 except:
2911 fRc = reporter.errorXcpt('Checking status of file #%d failed:' % (i,));
2912 else:
2913 if eFileStatus != vboxcon.FileStatus_Closed:
2914 fRc = reporter.error('Non-stale file #%d has status %d, expected %d'
2915 % (i, eFileStatus, vboxcon.FileStatus_Closed));
2916
2917 if fRc is True:
2918 reporter.log2('All non-stale files closed');
2919
2920 try: cFiles = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'files'));
2921 except: fRc = reporter.errorXcpt();
2922 else: reporter.log2('Final guest session file count: %d' % (cFiles,));
2923
2924 #
2925 # Now try to close the session and see what happens.
2926 # Note! Session closing is why we've been doing all the 'if fRc is True' stuff above rather than returning.
2927 #
2928 reporter.log2('Closing guest session ...');
2929 try:
2930 oGuestSession.close();
2931 except:
2932 fRc = reporter.errorXcpt('Testing for stale processes failed:');
2933
2934 return (fRc, oTxsSession);
2935
2936 #def testGuestCtrlSessionDirRefs(self, oSession, oTxsSession, oTestVm):
2937 # """
2938 # Tests the guest session directory reference handling.
2939 # """
2940
2941 # fRc = True;
2942 # return (fRc, oTxsSession);
2943
2944 def testGuestCtrlSessionProcRefs(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
2945 """
2946 Tests the guest session process reference handling.
2947 """
2948
2949 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
2950 asArgs = [sShell,];
2951
2952 # Use credential defaults.
2953 oCreds = tdCtxCreds();
2954 oCreds.applyDefaultsIfNotSet(oTestVm);
2955
2956 # Number of guest processes per group to create.
2957 cProcsPerGroup = 10;
2958
2959 #
2960 # Start a session.
2961 #
2962 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
2963 try:
2964 oGuest = oSession.o.console.guest;
2965 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionProcRefs");
2966 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
2967 except:
2968 return (reporter.errorXcpt(), oTxsSession);
2969
2970 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
2971 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
2972 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
2973 reporter.log('Session successfully started');
2974
2975 #
2976 # Fire off forever-running processes and "forget" them (stale entries).
2977 # For them we don't have any references anymore intentionally.
2978 #
2979 reporter.log('Starting stale processes...');
2980 fRc = True;
2981 for i in xrange(0, cProcsPerGroup):
2982 try:
2983 reporter.log2('Starting stale process #%d...' % (i));
2984 self.processCreateWrapper(oGuestSession, sShell, asArgs, "", # Working directory.
2985 [], # Environment changes.
2986 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], 30 * 1000);
2987 # Note: Not keeping a process reference from the created process above is intentional and part of the test!
2988
2989 # Note: Use a timeout in the call above for not letting the stale processes
2990 # hanging around forever. This can happen if the installed Guest Additions
2991 # do not support terminating guest processes.
2992 except:
2993 fRc = reporter.errorXcpt('Creating stale process #%d failed:' % (i,));
2994 break;
2995
2996 if fRc:
2997 reporter.log2('Starting stale processes successful');
2998 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
2999 except: fRc = reporter.errorXcpt();
3000 else:
3001 reporter.log2('Proccess count is: %d' % (cProcs));
3002 if cProcs != cProcsPerGroup:
3003 fRc = reporter.error('Got %d stale processes, expected %d (stale)' % (cProcs, cProcsPerGroup));
3004
3005 if fRc:
3006 #
3007 # Fire off non-stale processes and wait for termination.
3008 #
3009 if oTestVm.isWindows() or oTestVm.isOS2():
3010 asArgs = [ sShell, '/C', 'dir', '/S', self.oTstDrv.getGuestSystemDir(oTestVm), ];
3011 else:
3012 asArgs = [ sShell, '-c', 'ls -la ' + self.oTstDrv.getGuestSystemDir(oTestVm), ];
3013 reporter.log('Starting non-stale processes...');
3014 aoProcs = [];
3015 for i in xrange(0, cProcsPerGroup):
3016 try:
3017 reporter.log2('Starting non-stale process #%d...' % (i));
3018 oCurProc = self.processCreateWrapper(oGuestSession, sShell, asArgs,
3019 "", # Working directory.
3020 [], [], 0); # Infinite timeout.
3021 aoProcs.append(oCurProc);
3022 except:
3023 fRc = reporter.errorXcpt('Creating non-stale process #%d failed:' % (i,));
3024 break;
3025
3026 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3027 except: fRc = reporter.errorXcpt();
3028 else:
3029 reporter.log2('Proccess count is: %d' % (cProcs));
3030
3031 reporter.log('Waiting for non-stale processes to terminate...');
3032 for i, oProcess in enumerate(aoProcs):
3033 try:
3034 reporter.log('Waiting for non-stale process #%d...' % (i));
3035 eWaitResult = oProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 30 * 1000);
3036 eProcessStatus = oProcess.status;
3037 except:
3038 fRc = reporter.errorXcpt('Waiting for non-stale process #%d failed:' % (i,));
3039 else:
3040 if eProcessStatus != vboxcon.ProcessStatus_TerminatedNormally:
3041 fRc = reporter.error('Waiting for non-stale processes #%d resulted in status %d, expected %d (wr=%d)'
3042 % (i, eProcessStatus, vboxcon.ProcessStatus_TerminatedNormally, eWaitResult));
3043 if fRc:
3044 reporter.log('All non-stale processes ended successfully');
3045
3046 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3047 except: fRc = reporter.errorXcpt();
3048 else:
3049 reporter.log2('Proccess count is: %d' % (cProcs));
3050
3051 # Here we count the stale processes (that is, processes we don't have a reference
3052 # anymore for) and the started + ended non-stale processes (that we still keep
3053 # a reference in aoProcesses[] for).
3054 cProcsExpected = cProcsPerGroup * 2;
3055 if cProcs != cProcsExpected:
3056 fRc = reporter.error('Got %d total processes, expected %d (stale vs. non-stale)' \
3057 % (cProcs, cProcsExpected));
3058 #
3059 # Fire off non-stale blocking processes which are terminated via terminate().
3060 #
3061 if oTestVm.isWindows() or oTestVm.isOS2():
3062 sCmd = sShell;
3063 asArgs = [ sCmd, '/C', 'pause'];
3064 else:
3065 sCmd = '/usr/bin/yes';
3066 asArgs = [ sCmd ];
3067 reporter.log('Starting blocking processes...');
3068 aoProcs = [];
3069 for i in xrange(0, cProcsPerGroup):
3070 try:
3071 reporter.log2('Starting blocking process #%d...' % (i));
3072 oCurProc = self.processCreateWrapper(oGuestSession, sCmd, asArgs,
3073 "", # Working directory.
3074 [], [], 30 * 1000);
3075
3076 # Note: Use a timeout in the call above for not letting the stale processes
3077 # hanging around forever. This can happen if the installed Guest Additions
3078 # do not support terminating guest processes.
3079 try:
3080 reporter.log('Waiting for blocking process #%d getting started...' % (i));
3081 eWaitResult = oCurProc.waitForArray([ vboxcon.ProcessWaitForFlag_Start, ], 30 * 1000);
3082 eProcessStatus = oCurProc.status;
3083 except:
3084 fRc = reporter.errorXcpt('Waiting for blocking process #%d failed:' % (i,));
3085 else:
3086 if eProcessStatus != vboxcon.ProcessStatus_Started:
3087 fRc = reporter.error('Waiting for blocking processes #%d resulted in status %d, expected %d (wr=%d)'
3088 % (i, eProcessStatus, vboxcon.ProcessStatus_Started, eWaitResult));
3089 aoProcs.append(oCurProc);
3090 except:
3091 fRc = reporter.errorXcpt('Creating blocking process #%d failed:' % (i,));
3092 break;
3093
3094 if fRc:
3095 reporter.log2('Starting blocking processes successful');
3096
3097 reporter.log2('Terminating blocking processes...');
3098 for i, oProcess in enumerate(aoProcs):
3099 try:
3100 reporter.log('Terminating blocking process #%d...' % (i));
3101 oProcess.terminate();
3102 except: # Termination might not be supported, just skip and log it.
3103 reporter.logXcpt('Termination of blocking process #%d failed, skipped:' % (i,));
3104 if self.oTstDrv.fpApiVer >= 6.1: # Termination is supported since 5.2 or so.
3105 fRc = False;
3106 if fRc:
3107 reporter.log('All blocking processes were terminated successfully');
3108
3109 try: cProcs = len(self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes'));
3110 except: fRc = reporter.errorXcpt();
3111 else:
3112 # There still should be 20 processes because we just terminated the 10 blocking ones above.
3113 cProcsExpected = cProcsPerGroup * 2;
3114 if cProcs != cProcsExpected:
3115 fRc = reporter.error('Got %d total processes, expected %d (final)' % (cProcs, cProcsExpected));
3116 reporter.log2('Final guest session processes count: %d' % (cProcs,));
3117
3118 if not fRc:
3119 aoProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3120 for i, oProc in enumerate(aoProcs):
3121 try:
3122 aoArgs = self.oTstDrv.oVBoxMgr.getArray(oProc, 'arguments');
3123 reporter.log('Process %d (\'%s\') still around, status is %d' \
3124 % (i, ' '.join([str(x) for x in aoArgs]), oProc.status));
3125 except:
3126 reporter.errorXcpt('Process lookup failed:');
3127 #
3128 # Now try to close the session and see what happens.
3129 #
3130 reporter.log('Closing guest session ...');
3131 try:
3132 oGuestSession.close();
3133 except:
3134 fRc = reporter.errorXcpt('Closing session for testing process references failed:');
3135
3136 return (fRc, oTxsSession);
3137
3138 def testGuestCtrlExec(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals,too-many-statements
3139 """
3140 Tests the basic execution feature.
3141 """
3142
3143 # Paths:
3144 sVBoxControl = None; # Only available on supported Windows guests.
3145 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3146 sShellOpt = '/C' if oTestVm.isWindows() or oTestVm.isOS2() else '-c';
3147 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3148 sTempDir = self.oTstDrv.getGuestTempDir(oTestVm);
3149 sFileForReading = self.oTstDrv.getGuestSystemFileForReading(oTestVm);
3150 if oTestVm.isWindows() or oTestVm.isOS2():
3151 sImageOut = self.oTstDrv.getGuestSystemShell(oTestVm);
3152 if oTestVm.isWindows():
3153 sVBoxControl = oTestVm.pathJoin(self.oTstDrv.getGuestSystemAdminDir(oTestVm), 'VBoxControl.exe');
3154 else:
3155 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3156 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/ls", fIgnoreErrors = True):
3157 sImageOut = "/bin/ls";
3158 else:
3159 sImageOut = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'ls');
3160 if oTestVm.isLinux(): ## @todo check solaris and darwin.
3161 sVBoxControl = "/usr/bin/VBoxControl"; # Symlink
3162
3163 # Use credential defaults.
3164 oCreds = tdCtxCreds();
3165 oCreds.applyDefaultsIfNotSet(oTestVm);
3166
3167 atInvalid = [
3168 # Invalid parameters.
3169 [ tdTestExec(), tdTestResultExec() ],
3170 # Non-existent / invalid image.
3171 [ tdTestExec(sCmd = "non-existent"), tdTestResultExec() ],
3172 [ tdTestExec(sCmd = "non-existent2"), tdTestResultExec() ],
3173 # Use an invalid format string.
3174 [ tdTestExec(sCmd = "%$%%%&"), tdTestResultExec() ],
3175 # More stuff.
3176 [ tdTestExec(sCmd = u"ƒ‰‹ˆ÷‹¸"), tdTestResultExec() ],
3177 [ tdTestExec(sCmd = "???://!!!"), tdTestResultExec() ],
3178 [ tdTestExec(sCmd = "<>!\\"), tdTestResultExec() ],
3179 # Enable as soon as ERROR_BAD_DEVICE is implemented.
3180 #[ tdTestExec(sCmd = "CON", tdTestResultExec() ],
3181 ];
3182
3183 atExec = [];
3184 if oTestVm.isWindows() or oTestVm.isOS2():
3185 if oTestVm.sKind == 'WindowsNT4':
3186 # For whatever reason NT4 SP6 (tst-nt4sp6) returns exit code 2 for existing *and* non-existing files.
3187 # I've manually checked that on the VM itself, so this is *not* a bug in the Guest Control code.
3188 # So we have to tweak the expected exit codes here in order to make the following tests pass.
3189 iExitCodeForExistingFiles = 2
3190 iExitCodeForNonExistingFiles = 2
3191 else:
3192 iExitCodeForExistingFiles = 0
3193 iExitCodeForNonExistingFiles = 1
3194 atExec += [
3195 # Basic execution.
3196 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3197 tdTestResultExec(fRc = True) ],
3198 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sFileForReading ]),
3199 tdTestResultExec(fRc = True, iExitCode = iExitCodeForExistingFiles) ],
3200 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir + '\\nonexist.dll' ]),
3201 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3202 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ]),
3203 tdTestResultExec(fRc = True, iExitCode = 1) ],
3204 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3205 tdTestResultExec(fRc = True, iExitCode = 1) ],
3206 # StdOut.
3207 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3208 tdTestResultExec(fRc = True) ],
3209 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ]),
3210 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3211 # StdErr.
3212 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3213 tdTestResultExec(fRc = True) ],
3214 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ]),
3215 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3216 # StdOut + StdErr.
3217 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3218 tdTestResultExec(fRc = True) ],
3219 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ]),
3220 tdTestResultExec(fRc = True, iExitCode = iExitCodeForNonExistingFiles) ],
3221 ];
3222
3223 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3224 atExec.extend([
3225 # Current working directory set (VBox >= 7.1).
3226 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '/C', 'dir', '/S', sSystemDir ]),
3227 tdTestResultExec(fRc = True) ]
3228 ]);
3229
3230 # atExec.extend([
3231 # FIXME: Failing tests.
3232 # Environment variables.
3233 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3234 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3235 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3236 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3237 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3238 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3239 # aEnv = [ 'TEST_FOO=BAR' ],
3240 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3241 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3242 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3243 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3244 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3245 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3246
3247 ## @todo Create some files (or get files) we know the output size of to validate output length!
3248 ## @todo Add task which gets killed at some random time while letting the guest output something.
3249 #];
3250 else:
3251 atExec += [
3252 # Basic execution.
3253 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '-R', sSystemDir ]),
3254 tdTestResultExec(fRc = True) ],
3255 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sFileForReading ]),
3256 tdTestResultExec(fRc = True) ],
3257 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '--wrong-parameter' ]),
3258 tdTestResultExec(fRc = True, iExitCode = 2) ],
3259 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/non/existent' ]),
3260 tdTestResultExec(fRc = True, iExitCode = 2) ],
3261 [ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'wrongcommand' ]),
3262 tdTestResultExec(fRc = True, iExitCode = 127) ],
3263 # StdOut.
3264 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3265 tdTestResultExec(fRc = True) ],
3266 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdout-non-existing' ]),
3267 tdTestResultExec(fRc = True, iExitCode = 2) ],
3268 # StdErr.
3269 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3270 tdTestResultExec(fRc = True) ],
3271 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stderr-non-existing' ]),
3272 tdTestResultExec(fRc = True, iExitCode = 2) ],
3273 # StdOut + StdErr.
3274 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, sSystemDir ]),
3275 tdTestResultExec(fRc = True) ],
3276 [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, 'stdouterr-non-existing' ]),
3277 tdTestResultExec(fRc = True, iExitCode = 2) ],
3278 ];
3279
3280 if self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
3281 atExec.extend([
3282 # Current working directory set (VBox >= 7.1).
3283 [ tdTestExec(sCmd = sImageOut, sCwd = sTempDir, asArgs = [ sImageOut, '-R', sSystemDir ]),
3284 tdTestResultExec(fRc = True) ]
3285 ]);
3286
3287 # atExec.extend([
3288 # FIXME: Failing tests.
3289 # Environment variables.
3290 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
3291 # tdTestResultExec(fRc = True, iExitCode = 1) ]
3292 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'windir' ],
3293 #
3294 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3295 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
3296 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3297 # aEnv = [ 'TEST_FOO=BAR' ],
3298 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3299 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
3300 # [ tdTestExec(sCmd = sImageOut, asArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
3301 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
3302 # afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3303 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ]
3304
3305 ## @todo Create some files (or get files) we know the output size of to validate output length!
3306 ## @todo Add task which gets killed at some random time while letting the guest output something.
3307 #];
3308
3309 #
3310 #for iExitCode in xrange(0, 127):
3311 # atExec.append([ tdTestExec(sCmd = sShell, asArgs = [ sShell, sShellOpt, 'exit %s' % iExitCode ]),
3312 # tdTestResultExec(fRc = True, iExitCode = iExitCode) ]);
3313
3314 if sVBoxControl \
3315 and self.oTstDrv.fpApiVer >= 6.0: # Investigate with this doesn't work on (<) 5.2.
3316 # Paths with spaces on windows.
3317 atExec.append([ tdTestExec(sCmd = sVBoxControl, asArgs = [ sVBoxControl, 'version' ],
3318 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3319 vboxcon.ProcessCreateFlag_WaitForStdErr ]),
3320 tdTestResultExec(fRc = True) ]);
3321
3322 # Test very long arguments. Be careful when tweaking this to not break the tests.
3323 # Regarding paths:
3324 # - We have RTPATH_BIG_MAX (64K)
3325 # - MSDN says 32K for CreateFileW()
3326 # - On Windows, each path component must not be longer than MAX_PATH (260), see
3327 # https://docs.microsoft.com/en-us/windows/win32/fileio/filesystem-functionality-comparison#limits
3328 #
3329 # Old(er) Windows OSes tend to crash in cmd.exe, so skip this on these OSes.
3330 if self.oTstDrv.fpApiVer >= 6.1 \
3331 and oTestVm.sKind not in ('WindowsNT4', 'Windows2000', 'WindowsXP', 'Windows2003'):
3332 sEndMarker = '--end-marker';
3333 if oTestVm.isWindows() \
3334 or oTestVm.isOS2():
3335 sCmd = sShell;
3336 else:
3337 # Really old guests (like OL 6) have their coreutils in /bin instead of /usr/bin.
3338 if self.oTstDrv.txsIsFile(oSession, oTxsSession, "/bin/echo", fIgnoreErrors = True):
3339 sCmd = "/bin/echo";
3340 else:
3341 sCmd = oTestVm.pathJoin(self.oTstDrv.getGuestSystemDir(oTestVm), 'echo');
3342
3343 for _ in xrange(0, 16):
3344 if oTestVm.isWindows() \
3345 or oTestVm.isOS2():
3346 asArgs = [ sShell, sShellOpt, "echo" ];
3347 else:
3348 asArgs = [ sCmd ];
3349
3350 # Append a random number of arguments with random length.
3351 for _ in xrange(0, self.oTestFiles.oRandom.randrange(1, 64)):
3352 asArgs.append(''.join(random.choice(string.ascii_lowercase)
3353 for _ in range(self.oTestFiles.oRandom.randrange(1, 196))));
3354
3355 asArgs.append(sEndMarker);
3356
3357 reporter.log2('asArgs=%s (%d args), type=%s' % (limitString(asArgs), len(asArgs), type(asArgs)));
3358
3359 ## @todo Check limits; on Ubuntu with 256KB IPRT returns VERR_NOT_IMPLEMENTED.
3360 # Use a higher timeout (15 min) than usual for these long checks.
3361 atExec.append([ tdTestExec(sCmd = sCmd, asArgs = asArgs,
3362 afFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut,
3363 vboxcon.ProcessCreateFlag_WaitForStdErr ],
3364 timeoutMS = 15 * 60 * 1000),
3365 tdTestResultExec(fRc = True) ]);
3366
3367 # Build up the final test array for the first batch.
3368 atTests = atInvalid + atExec;
3369
3370 #
3371 # First batch: One session per guest process.
3372 #
3373 reporter.log('One session per guest process ...');
3374 fRc = True;
3375 for (i, tTest) in enumerate(atTests):
3376 oCurTest = tTest[0] # type: tdTestExec
3377 oCurRes = tTest[1] # type: tdTestResultExec
3378 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3379 if not fRc:
3380 break;
3381 fRc2, oCurGuestSession = oCurTest.createSession('testGuestCtrlExec: Test #%d' % (i,));
3382 if fRc2 is not True:
3383 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3384 break;
3385 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession) and fRc;
3386 fRc = oCurTest.closeSession() and fRc;
3387
3388 reporter.log('Execution of all tests done, checking for stale sessions');
3389
3390 # No sessions left?
3391 try:
3392 aSessions = self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions');
3393 except:
3394 fRc = reporter.errorXcpt();
3395 else:
3396 cSessions = len(aSessions);
3397 if cSessions != 0:
3398 fRc = reporter.error('Found %d stale session(s), expected 0:' % (cSessions,));
3399 for (i, aSession) in enumerate(aSessions):
3400 try: reporter.log(' Stale session #%d ("%s")' % (aSession.id, aSession.name));
3401 except: reporter.errorXcpt();
3402
3403 if fRc is not True:
3404 return (fRc, oTxsSession);
3405
3406 reporter.log('Now using one guest session for all tests ...');
3407
3408 #
3409 # Second batch: One session for *all* guest processes.
3410 #
3411
3412 # Create session.
3413 reporter.log('Creating session for all tests ...');
3414 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start, ];
3415 try:
3416 oGuest = oSession.o.console.guest;
3417 oCurGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain,
3418 'testGuestCtrlExec: One session for all tests');
3419 except:
3420 return (reporter.errorXcpt(), oTxsSession);
3421
3422 try:
3423 eWaitResult = oCurGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3424 except:
3425 fRc = reporter.errorXcpt('Waiting for guest session to start failed:');
3426 else:
3427 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3428 fRc = reporter.error('Session did not start successfully, returned wait result: %d' % (eWaitResult,));
3429 else:
3430 reporter.log('Session successfully started');
3431
3432 # Do the tests within this session.
3433 for (i, tTest) in enumerate(atTests):
3434 oCurTest = tTest[0] # type: tdTestExec
3435 oCurRes = tTest[1] # type: tdTestResultExec
3436
3437 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3438 if not fRc:
3439 break;
3440 fRc = self.gctrlExecDoTest(i, oCurTest, oCurRes, oCurGuestSession);
3441 if fRc is False:
3442 break;
3443
3444 # Close the session.
3445 reporter.log2('Closing guest session ...');
3446 try:
3447 oCurGuestSession.close();
3448 oCurGuestSession = None;
3449 except:
3450 fRc = reporter.errorXcpt('Closing guest session failed:');
3451
3452 # No sessions left?
3453 reporter.log('Execution of all tests done, checking for stale sessions again');
3454 try: cSessions = len(self.oTstDrv.oVBoxMgr.getArray(oSession.o.console.guest, 'sessions'));
3455 except: fRc = reporter.errorXcpt();
3456 else:
3457 if cSessions != 0:
3458 fRc = reporter.error('Found %d stale session(s), expected 0' % (cSessions,));
3459 return (fRc, oTxsSession);
3460
3461 def threadForTestGuestCtrlSessionReboot(self, oGuestProcess):
3462 """
3463 Thread routine which waits for the stale guest process getting terminated (or some error)
3464 while the main test routine reboots the guest. It then compares the expected guest process result
3465 and logs an error if appropriate.
3466 """
3467 reporter.log('Waiting for process to get terminated at reboot ...');
3468 try:
3469 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate ], 5 * 60 * 1000);
3470 except:
3471 return reporter.errorXcpt('waitForArray failed');
3472 try:
3473 eStatus = oGuestProcess.status
3474 except:
3475 return reporter.errorXcpt('failed to get status (wait result %d)' % (eWaitResult,));
3476
3477 if eWaitResult == vboxcon.ProcessWaitResult_Terminate and eStatus == vboxcon.ProcessStatus_Down:
3478 reporter.log('Stale process was correctly terminated (status: down)');
3479 return True;
3480
3481 return reporter.error('Process wait across reboot failed: eWaitResult=%d, expected %d; eStatus=%d, expected %d'
3482 % (eWaitResult, vboxcon.ProcessWaitResult_Terminate, eStatus, vboxcon.ProcessStatus_Down,));
3483
3484 def testGuestCtrlSessionReboot(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3485 """
3486 Tests guest object notifications when a guest gets rebooted / shutdown.
3487
3488 These notifications gets sent from the guest sessions in order to make API clients
3489 aware of guest session changes.
3490
3491 To test that we create a stale guest process and trigger a reboot of the guest.
3492 """
3493
3494 ## @todo backport fixes to 6.0 and maybe 5.2
3495 if self.oTstDrv.fpApiVer <= 6.0:
3496 reporter.log('Skipping: Required fixes not yet backported!');
3497 return None;
3498
3499 # Use credential defaults.
3500 oCreds = tdCtxCreds();
3501 oCreds.applyDefaultsIfNotSet(oTestVm);
3502
3503 fRebooted = False;
3504 fRc = True;
3505
3506 #
3507 # Start a session.
3508 #
3509 aeWaitFor = [ vboxcon.GuestSessionWaitForFlag_Start ];
3510 try:
3511 oGuest = oSession.o.console.guest;
3512 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlSessionReboot");
3513 eWaitResult = oGuestSession.waitForArray(aeWaitFor, 30 * 1000);
3514 except:
3515 return (reporter.errorXcpt(), oTxsSession);
3516
3517 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3518 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3519 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3520 reporter.log('Session successfully started');
3521
3522 #
3523 # Create a process.
3524 #
3525 # That process will also be used later to see if the session cleanup worked upon reboot.
3526 #
3527 sImage = self.oTstDrv.getGuestSystemShell(oTestVm);
3528 asArgs = [ sImage, ];
3529 aEnv = [];
3530 afFlags = [];
3531 try:
3532 oGuestProcess = self.processCreateWrapper(oGuestSession, sImage, asArgs,
3533 "", # Working directory.
3534 aEnv, afFlags, 30 * 1000);
3535 except:
3536 fRc = reporter.error('Failed to start shell process (%s)' % (sImage,));
3537 else:
3538 try:
3539 eWaitResult = oGuestProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3540 except:
3541 fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3542 else:
3543 # Check the result and state:
3544 try: eStatus = oGuestProcess.status;
3545 except: fRc = reporter.errorXcpt('Waiting for shell process (%s) to start failed' % (sImage,));
3546 else:
3547 reporter.log2('Starting process wait result returned: %d; Process status is: %d' % (eWaitResult, eStatus,));
3548 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3549 fRc = reporter.error('wait for ProcessWaitForFlag_Start failed: %d, expected %d (Start)'
3550 % (eWaitResult, vboxcon.ProcessWaitResult_Start,));
3551 elif eStatus != vboxcon.ProcessStatus_Started:
3552 fRc = reporter.error('Unexpected process status after startup: %d, wanted %d (Started)'
3553 % (eStatus, vboxcon.ProcessStatus_Started,));
3554 else:
3555 # Create a thread that waits on the process to terminate
3556 reporter.log('Creating reboot thread ...');
3557 oThreadReboot = threading.Thread(target = self.threadForTestGuestCtrlSessionReboot,
3558 args = (oGuestProcess,),
3559 name = 'threadForTestGuestCtrlSessionReboot');
3560 oThreadReboot.setDaemon(True); # pylint: disable=deprecated-method
3561 oThreadReboot.start();
3562
3563 # Do the reboot.
3564 reporter.log('Rebooting guest and reconnecting TXS ...');
3565 (oSession, oTxsSession) = self.oTstDrv.txsRebootAndReconnectViaTcp(oSession, oTxsSession,
3566 cMsTimeout = 3 * 60000);
3567 if oSession \
3568 and oTxsSession:
3569 # Set reboot flag (needed later for session closing).
3570 fRebooted = True;
3571 else:
3572 reporter.error('Rebooting via TXS failed');
3573 try: oGuestProcess.terminate();
3574 except: reporter.logXcpt();
3575 fRc = False;
3576
3577 reporter.log('Waiting for thread to finish ...');
3578 oThreadReboot.join();
3579
3580 # Check that the guest session now still has the formerly guest process object created above,
3581 # but with the "down" status now (because of guest reboot).
3582 try:
3583 aoGuestProcs = self.oTstDrv.oVBoxMgr.getArray(oGuestSession, 'processes');
3584 if len(aoGuestProcs) == 1:
3585 enmProcSts = aoGuestProcs[0].status;
3586 if enmProcSts != vboxcon.ProcessStatus_Down:
3587 fRc = reporter.error('Old guest process (before reboot) has status %d, expected %s' \
3588 % (enmProcSts, vboxcon.ProcessStatus_Down));
3589 else:
3590 fRc = reporter.error('Old guest session (before reboot) has %d processes registered, expected 1' \
3591 % (len(aoGuestProcs)));
3592 except:
3593 fRc = reporter.errorXcpt();
3594 #
3595 # Try make sure we don't leave with a stale process on failure.
3596 #
3597 try: oGuestProcess.terminate();
3598 except: reporter.logXcpt();
3599
3600 #
3601 # Close the session.
3602 #
3603 reporter.log2('Closing guest session ...');
3604 try:
3605 oGuestSession.close();
3606 except:
3607 # Closing the guest session will fail when the guest reboot has been triggered,
3608 # as the session object will be cleared on a guest reboot.
3609 if fRebooted:
3610 reporter.logXcpt('Closing guest session failed, good (guest rebooted)');
3611 else: # ... otherwise this (still) should succeed. Report so if it doesn't.
3612 reporter.errorXcpt('Closing guest session failed');
3613
3614 return (fRc, oTxsSession);
3615
3616 def testGuestCtrlExecTimeout(self, oSession, oTxsSession, oTestVm):
3617 """
3618 Tests handling of timeouts of started guest processes.
3619 """
3620
3621 sShell = self.oTstDrv.getGuestSystemShell(oTestVm);
3622
3623 # Use credential defaults.
3624 oCreds = tdCtxCreds();
3625 oCreds.applyDefaultsIfNotSet(oTestVm);
3626
3627 #
3628 # Create a session.
3629 #
3630 try:
3631 oGuest = oSession.o.console.guest;
3632 oGuestSession = oGuest.createSession(oCreds.sUser, oCreds.sPassword, oCreds.sDomain, "testGuestCtrlExecTimeout");
3633 eWaitResult = oGuestSession.waitForArray([ vboxcon.GuestSessionWaitForFlag_Start, ], 30 * 1000);
3634 except:
3635 return (reporter.errorXcpt(), oTxsSession);
3636
3637 # Be nice to Guest Additions < 4.3: They don't support session handling and therefore return WaitFlagNotSupported.
3638 if eWaitResult not in (vboxcon.GuestSessionWaitResult_Start, vboxcon.GuestSessionWaitResult_WaitFlagNotSupported):
3639 return (reporter.error('Session did not start successfully - wait error: %d' % (eWaitResult,)), oTxsSession);
3640 reporter.log('Session successfully started');
3641
3642 #
3643 # Create a process which never terminates and should timeout when
3644 # waiting for termination.
3645 #
3646 fRc = True;
3647 try:
3648 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [ sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3649 "", # Working directory.
3650 [], [], 30 * 1000);
3651 except:
3652 fRc = reporter.errorXcpt();
3653 else:
3654 reporter.log('Waiting for process 1 being started ...');
3655 try:
3656 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3657 except:
3658 fRc = reporter.errorXcpt();
3659 else:
3660 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3661 fRc = reporter.error('Waiting for process 1 to start failed, got status %d' % (eWaitResult,));
3662 else:
3663 for msWait in (1, 32, 2000,):
3664 reporter.log('Waiting for process 1 to time out within %sms ...' % (msWait,));
3665 try:
3666 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], msWait);
3667 except:
3668 fRc = reporter.errorXcpt();
3669 break;
3670 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3671 fRc = reporter.error('Waiting for process 1 did not time out in %sms as expected: %d'
3672 % (msWait, eWaitResult,));
3673 break;
3674 reporter.log('Waiting for process 1 timed out in %u ms, good' % (msWait,));
3675
3676 try:
3677 oCurProcess.terminate();
3678 except:
3679 reporter.errorXcpt();
3680 oCurProcess = None;
3681
3682 #
3683 # Create another process that doesn't terminate, but which will be killed by VBoxService
3684 # because it ran out of execution time (3 seconds).
3685 #
3686 try:
3687 oCurProcess = self.processCreateWrapper(oGuestSession, sShell, [sShell,] if self.oTstDrv.fpApiVer >= 5.0 else [],
3688 "", # Working directory.
3689 [], [], 3 * 1000);
3690 except:
3691 fRc = reporter.errorXcpt();
3692 else:
3693 reporter.log('Waiting for process 2 being started ...');
3694 try:
3695 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Start ], 30 * 1000);
3696 except:
3697 fRc = reporter.errorXcpt();
3698 else:
3699 if eWaitResult != vboxcon.ProcessWaitResult_Start:
3700 fRc = reporter.error('Waiting for process 2 to start failed, got status %d' % (eWaitResult,));
3701 else:
3702 reporter.log('Waiting for process 2 to get killed for running out of execution time ...');
3703 try:
3704 eWaitResult = oCurProcess.waitForArray([ vboxcon.ProcessWaitForFlag_Terminate, ], 15 * 1000);
3705 except:
3706 fRc = reporter.errorXcpt();
3707 else:
3708 if eWaitResult != vboxcon.ProcessWaitResult_Timeout:
3709 fRc = reporter.error('Waiting for process 2 did not time out when it should, got wait result %d'
3710 % (eWaitResult,));
3711 else:
3712 reporter.log('Waiting for process 2 did not time out, good: %s' % (eWaitResult,));
3713 try:
3714 eStatus = oCurProcess.status;
3715 except:
3716 fRc = reporter.errorXcpt();
3717 else:
3718 if eStatus != vboxcon.ProcessStatus_TimedOutKilled:
3719 fRc = reporter.error('Status of process 2 wrong; excepted %d, got %d'
3720 % (vboxcon.ProcessStatus_TimedOutKilled, eStatus));
3721 else:
3722 reporter.log('Status of process 2 is TimedOutKilled (%d) is it should be.'
3723 % (vboxcon.ProcessStatus_TimedOutKilled,));
3724 try:
3725 oCurProcess.terminate();
3726 except:
3727 reporter.logXcpt();
3728 oCurProcess = None;
3729
3730 #
3731 # Clean up the session.
3732 #
3733 try:
3734 oGuestSession.close();
3735 except:
3736 fRc = reporter.errorXcpt();
3737
3738 return (fRc, oTxsSession);
3739
3740 def testGuestCtrlDirCreate(self, oSession, oTxsSession, oTestVm):
3741 """
3742 Tests creation of guest directories.
3743 """
3744
3745 sScratch = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'testGuestCtrlDirCreate');
3746
3747 atTests = [
3748 # Invalid stuff.
3749 [ tdTestDirCreate(sDirectory = '' ), tdTestResultFailure() ],
3750 # More unusual stuff.
3751 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '.') ), tdTestResultFailure() ],
3752 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin('..', '..') ), tdTestResultFailure() ],
3753 [ tdTestDirCreate(sDirectory = '..' ), tdTestResultFailure() ],
3754 [ tdTestDirCreate(sDirectory = '../' ), tdTestResultFailure() ],
3755 [ tdTestDirCreate(sDirectory = '../../' ), tdTestResultFailure() ],
3756 [ tdTestDirCreate(sDirectory = '/' ), tdTestResultFailure() ],
3757 [ tdTestDirCreate(sDirectory = '/..' ), tdTestResultFailure() ],
3758 [ tdTestDirCreate(sDirectory = '/../' ), tdTestResultFailure() ],
3759 ];
3760 if oTestVm.isWindows() or oTestVm.isOS2():
3761 atTests.extend([
3762 [ tdTestDirCreate(sDirectory = 'C:\\' ), tdTestResultFailure() ],
3763 [ tdTestDirCreate(sDirectory = 'C:\\..' ), tdTestResultFailure() ],
3764 [ tdTestDirCreate(sDirectory = 'C:\\..\\' ), tdTestResultFailure() ],
3765 [ tdTestDirCreate(sDirectory = 'C:/' ), tdTestResultFailure() ],
3766 [ tdTestDirCreate(sDirectory = 'C:/.' ), tdTestResultFailure() ],
3767 [ tdTestDirCreate(sDirectory = 'C:/./' ), tdTestResultFailure() ],
3768 [ tdTestDirCreate(sDirectory = 'C:/..' ), tdTestResultFailure() ],
3769 [ tdTestDirCreate(sDirectory = 'C:/../' ), tdTestResultFailure() ],
3770 [ tdTestDirCreate(sDirectory = '\\\\uncrulez\\foo' ), tdTestResultFailure() ],
3771 ]);
3772 atTests.extend([
3773 # Existing directories and files.
3774 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemDir(oTestVm) ), tdTestResultFailure() ],
3775 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemShell(oTestVm) ), tdTestResultFailure() ],
3776 [ tdTestDirCreate(sDirectory = self.oTstDrv.getGuestSystemFileForReading(oTestVm) ), tdTestResultFailure() ],
3777 # Creating directories.
3778 [ tdTestDirCreate(sDirectory = sScratch ), tdTestResultSuccess() ],
3779 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3780 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3781 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo', 'bar', 'baz'),
3782 afFlags = (vboxcon.DirectoryCreateFlag_Parents,) ), tdTestResultSuccess() ],
3783 # Try format strings as directories.
3784 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo%sbar%sbaz%d' )), tdTestResultSuccess() ],
3785 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, '%f%%boo%%bar%RI32' )), tdTestResultSuccess() ],
3786 # Long random names.
3787 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(36, 28))),
3788 tdTestResultSuccess() ],
3789 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(140, 116))),
3790 tdTestResultSuccess() ],
3791 # Too long names. ASSUMES a guests has a 255 filename length limitation.
3792 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3793 tdTestResultFailure() ],
3794 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, self.oTestFiles.generateFilenameEx(2048, 256))),
3795 tdTestResultFailure() ],
3796 # Missing directory in path.
3797 [ tdTestDirCreate(sDirectory = oTestVm.pathJoin(sScratch, 'foo1', 'bar') ), tdTestResultFailure() ],
3798 ]);
3799
3800 fRc = True;
3801 for (i, tTest) in enumerate(atTests):
3802 oCurTest = tTest[0] # type: tdTestDirCreate
3803 oCurRes = tTest[1] # type: tdTestResult
3804 reporter.log('Testing #%d, sDirectory="%s" ...' % (i, limitString(oCurTest.sDirectory),));
3805
3806 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3807 if not fRc:
3808 break;
3809 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreate: Test #%d' % (i,));
3810 if fRc is False:
3811 return reporter.error('Test #%d failed: Could not create session' % (i,));
3812
3813 fRc = self.gctrlCreateDir(oCurTest, oCurRes, oCurGuestSession);
3814
3815 fRc = oCurTest.closeSession() and fRc;
3816 if fRc is False:
3817 fRc = reporter.error('Test #%d failed' % (i,));
3818
3819 return (fRc, oTxsSession);
3820
3821 def testGuestCtrlDirCreateTemp(self, oSession, oTxsSession, oTestVm): # pylint: disable=too-many-locals
3822 """
3823 Tests creation of temporary directories.
3824 """
3825
3826 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3827 atTests = [
3828 # Invalid stuff (template must have one or more trailin 'X'es (upper case only), or a cluster of three or more).
3829 [ tdTestDirCreateTemp(sDirectory = ''), tdTestResultFailure() ],
3830 [ tdTestDirCreateTemp(sDirectory = sSystemDir, fMode = 1234), tdTestResultFailure() ],
3831 [ tdTestDirCreateTemp(sTemplate = 'xXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3832 [ tdTestDirCreateTemp(sTemplate = 'xxx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3833 [ tdTestDirCreateTemp(sTemplate = 'XXx', sDirectory = sSystemDir, fMode = 0o700), tdTestResultFailure() ],
3834 [ tdTestDirCreateTemp(sTemplate = 'bar', sDirectory = 'whatever', fMode = 0o700), tdTestResultFailure() ],
3835 [ tdTestDirCreateTemp(sTemplate = 'foo', sDirectory = 'it is not used', fMode = 0o700), tdTestResultFailure() ],
3836 [ tdTestDirCreateTemp(sTemplate = 'X,so', sDirectory = 'pointless test', fMode = 0o700), tdTestResultFailure() ],
3837 # Non-existing stuff.
3838 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX',
3839 sDirectory = oTestVm.pathJoin(self.oTstDrv.getGuestTempDir(oTestVm), 'non', 'existing')),
3840 tdTestResultFailure() ],
3841 # Working stuff:
3842 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3843 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3844 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)), tdTestResultFailure() ],
3845 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3846 tdTestResultFailure() ],
3847 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3848 tdTestResultFailure() ],
3849 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3850 tdTestResultFailure() ],
3851 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm)),
3852 tdTestResultFailure() ],
3853 ];
3854
3855 if self.oTstDrv.fpApiVer >= 7.0:
3856 # Weird mode set.
3857 atTests.extend([
3858 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o42333),
3859 tdTestResultFailure() ]
3860 ]);
3861 # Same as working stuff above, but with a different mode set.
3862 atTests.extend([
3863 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3864 tdTestResultFailure() ],
3865 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3866 tdTestResultFailure() ],
3867 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3868 tdTestResultFailure() ],
3869 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3870 tdTestResultFailure() ],
3871 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3872 tdTestResultFailure() ],
3873 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3874 tdTestResultFailure() ],
3875 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fMode = 0o777),
3876 tdTestResultFailure() ]
3877 ]);
3878 # Same as working stuff above, but with secure mode set.
3879 atTests.extend([
3880 [ tdTestDirCreateTemp(sTemplate = 'X', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
3881 tdTestResultFailure() ],
3882 [ tdTestDirCreateTemp(sTemplate = 'XX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
3883 tdTestResultFailure() ],
3884 [ tdTestDirCreateTemp(sTemplate = 'XXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
3885 tdTestResultFailure() ],
3886 [ tdTestDirCreateTemp(sTemplate = 'XXXXXXX', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm), fSecure = True),
3887 tdTestResultFailure() ],
3888 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
3889 fSecure = True),
3890 tdTestResultFailure() ],
3891 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
3892 fSecure = True),
3893 tdTestResultFailure() ],
3894 [ tdTestDirCreateTemp(sTemplate = 'tmpXXXtst', sDirectory = self.oTstDrv.getGuestTempDir(oTestVm),
3895 fSecure = True),
3896 tdTestResultFailure() ]
3897 ]);
3898
3899 fRc = True;
3900 for (i, tTest) in enumerate(atTests):
3901 oCurTest = tTest[0] # type: tdTestDirCreateTemp
3902 oCurRes = tTest[1] # type: tdTestResult
3903 reporter.log('Testing #%d, sTemplate="%s", fMode=%#o, path="%s", secure="%s" ...' %
3904 (i, oCurTest.sTemplate, oCurTest.fMode, oCurTest.sDirectory, oCurTest.fSecure));
3905
3906 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
3907 if not fRc:
3908 break;
3909 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirCreateTemp: Test #%d' % (i,));
3910 if fRc is False:
3911 fRc = reporter.error('Test #%d failed: Could not create session' % (i,));
3912 break;
3913
3914 sDirTemp = '';
3915 try:
3916 sDirTemp = oCurGuestSession.directoryCreateTemp(oCurTest.sTemplate, oCurTest.fMode,
3917 oCurTest.sDirectory, oCurTest.fSecure);
3918 except:
3919 if oCurRes.fRc is True:
3920 fRc = reporter.errorXcpt('Creating temp directory "%s" failed:' % (oCurTest.sDirectory,));
3921 else:
3922 reporter.logXcpt('Creating temp directory "%s" failed expectedly, skipping:' % (oCurTest.sDirectory,));
3923 else:
3924 reporter.log2('Temporary directory is: "%s"' % (limitString(sDirTemp),));
3925 if not sDirTemp:
3926 fRc = reporter.error('Resulting directory is empty!');
3927 else:
3928 ## @todo This does not work for some unknown reason.
3929 #try:
3930 # if self.oTstDrv.fpApiVer >= 5.0:
3931 # fExists = oCurGuestSession.directoryExists(sDirTemp, False);
3932 # else:
3933 # fExists = oCurGuestSession.directoryExists(sDirTemp);
3934 #except:
3935 # fRc = reporter.errorXcpt('sDirTemp=%s' % (sDirTemp,));
3936 #else:
3937 # if fExists is not True:
3938 # fRc = reporter.error('Test #%d failed: Temporary directory "%s" does not exists (%s)'
3939 # % (i, sDirTemp, fExists));
3940 try:
3941 oFsObjInfo = oCurGuestSession.fsObjQueryInfo(sDirTemp, False);
3942 eType = oFsObjInfo.type;
3943 except:
3944 fRc = reporter.errorXcpt('sDirTemp="%s"' % (sDirTemp,));
3945 else:
3946 reporter.log2('%s: eType=%s (dir=%d)' % (limitString(sDirTemp), eType, vboxcon.FsObjType_Directory,));
3947 if eType != vboxcon.FsObjType_Directory:
3948 fRc = reporter.error('Temporary directory "%s" not created as a directory: eType=%d'
3949 % (sDirTemp, eType));
3950 fRc = oCurTest.closeSession() and fRc;
3951 return (fRc, oTxsSession);
3952
3953 def testGuestCtrlDirRead(self, oSession, oTxsSession, oTestVm):
3954 """
3955 Tests opening and reading (enumerating) guest directories.
3956 """
3957
3958 sSystemDir = self.oTstDrv.getGuestSystemDir(oTestVm);
3959 atTests = [
3960 # Invalid stuff.
3961 [ tdTestDirRead(sDirectory = ''), tdTestResultDirRead() ],
3962 [ tdTestDirRead(sDirectory = sSystemDir, afFlags = [ 1234 ]), tdTestResultDirRead() ],
3963 [ tdTestDirRead(sDirectory = sSystemDir, sFilter = '*.foo'), tdTestResultDirRead() ],
3964 # Non-existing stuff.
3965 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'really-no-such-subdir')), tdTestResultDirRead() ],
3966 [ tdTestDirRead(sDirectory = oTestVm.pathJoin(sSystemDir, 'non', 'existing')), tdTestResultDirRead() ],
3967 ];
3968
3969 if oTestVm.isWindows() or oTestVm.isOS2():
3970 atTests.extend([
3971 # More unusual stuff.
3972 [ tdTestDirRead(sDirectory = 'z:\\'), tdTestResultDirRead() ],
3973 [ tdTestDirRead(sDirectory = '\\\\uncrulez\\foo'), tdTestResultDirRead() ],
3974 ]);
3975
3976 # Read the system directory (ASSUMES at least 5 files in it):
3977 # Windows 7+ has inaccessible system32/com/dmp directory that screws up this test, so skip it on windows:
3978 if not oTestVm.isWindows():
3979 atTests.append([ tdTestDirRead(sDirectory = sSystemDir),
3980 tdTestResultDirRead(fRc = True, cFiles = -5, cDirs = None) ]);
3981 ## @todo trailing slash
3982
3983 # Read from the test file set.
3984 atTests.extend([
3985 [ tdTestDirRead(sDirectory = self.oTestFiles.oEmptyDir.sPath),
3986 tdTestResultDirRead(fRc = True, cFiles = 0, cDirs = 0, cOthers = 0) ],
3987 [ tdTestDirRead(sDirectory = self.oTestFiles.oManyDir.sPath),
3988 tdTestResultDirRead(fRc = True, cFiles = len(self.oTestFiles.oManyDir.aoChildren), cDirs = 0, cOthers = 0) ],
3989 [ tdTestDirRead(sDirectory = self.oTestFiles.oTreeDir.sPath),
3990 tdTestResultDirRead(fRc = True, cFiles = self.oTestFiles.cTreeFiles, cDirs = self.oTestFiles.cTreeDirs,
3991 cOthers = self.oTestFiles.cTreeOthers) ],
3992 ]);
3993
3994
3995 fRc = True;
3996 for (i, tTest) in enumerate(atTests):
3997 oCurTest = tTest[0] # type: tdTestExec
3998 oCurRes = tTest[1] # type: tdTestResultDirRead
3999
4000 reporter.log('Testing #%d, dir="%s" ...' % (i, oCurTest.sDirectory));
4001 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4002 if not fRc:
4003 break;
4004 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: Test #%d' % (i,));
4005 if fRc is not True:
4006 break;
4007 fUseDirList = False;
4008 cEntriesPerRead = random.randrange(1, 32768);
4009 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4010 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4011 # Listing directories only is available for >= VBox 7.1.
4012 fUseDirList = random.choice( [True, False] );
4013 (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc,
4014 fUseDirList, cEntriesPerRead);
4015 fRc = oCurTest.closeSession() and fRc;
4016
4017 reporter.log2('Test #%d: Returned %d directories, %d files total' % (i, cDirs, cFiles));
4018 if fRc2 is oCurRes.fRc:
4019 if fRc2 is True:
4020 if oCurRes.cFiles is None:
4021 pass; # ignore
4022 elif oCurRes.cFiles >= 0 and cFiles != oCurRes.cFiles:
4023 fRc = reporter.error('Test #%d failed: Got %d files, expected %d' % (i, cFiles, oCurRes.cFiles));
4024 elif oCurRes.cFiles < 0 and cFiles < -oCurRes.cFiles:
4025 fRc = reporter.error('Test #%d failed: Got %d files, expected at least %d'
4026 % (i, cFiles, -oCurRes.cFiles));
4027 if oCurRes.cDirs is None:
4028 pass; # ignore
4029 elif oCurRes.cDirs >= 0 and cDirs != oCurRes.cDirs:
4030 fRc = reporter.error('Test #%d failed: Got %d directories, expected %d' % (i, cDirs, oCurRes.cDirs));
4031 elif oCurRes.cDirs < 0 and cDirs < -oCurRes.cDirs:
4032 fRc = reporter.error('Test #%d failed: Got %d directories, expected at least %d'
4033 % (i, cDirs, -oCurRes.cDirs));
4034 if oCurRes.cOthers is None:
4035 pass; # ignore
4036 elif oCurRes.cOthers >= 0 and cOthers != oCurRes.cOthers:
4037 fRc = reporter.error('Test #%d failed: Got %d other types, expected %d' % (i, cOthers, oCurRes.cOthers));
4038 elif oCurRes.cOthers < 0 and cOthers < -oCurRes.cOthers:
4039 fRc = reporter.error('Test #%d failed: Got %d other types, expected at least %d'
4040 % (i, cOthers, -oCurRes.cOthers));
4041
4042 else:
4043 fRc = reporter.error('Test #%d failed: Got %s, expected %s' % (i, fRc2, oCurRes.fRc));
4044
4045
4046 #
4047 # Go over a few directories in the test file set and compare names,
4048 # types and sizes rather than just the counts like we did above.
4049 #
4050 if fRc is True:
4051 oCurTest = tdTestDirRead();
4052 fRc = oCurTest.setEnvironment(oSession, oTxsSession, oTestVm);
4053 if fRc:
4054 fRc, oCurGuestSession = oCurTest.createSession('testGuestCtrlDirRead: gctrlReadDirTree2');
4055 if fRc is True:
4056 for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
4057 reporter.log('Checking "%s" ...' % (oDir.sPath,));
4058 fUseDirList = False;
4059 cEntriesPerRead = random.randrange(1, 32768);
4060 if self.oTstDrv.fpApiVer >= 7.1 and self.oTstDrv.uRevision >= 156485 \
4061 and self.oTstDrv.isVersionEqualOrBigger(self.tpAdditionsVer, "7.1.0"):
4062 # Listing directories only is available for >= VBox 7.1.
4063 fUseDirList = random.choice( [True, False] );
4064 fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir, fUseDirList, cEntriesPerRead) and fRc;
4065 fRc = oCurTest.closeSession() and fRc;
4066
4067 return (fRc, oTxsSession);
4068
4069
4070 def testGuestCtrlFileRemove(self, oSession, oTxsSession, oTestVm):
4071 """
4072 Tests removing guest files.
4073 """
4074
4075 #
4076 # Create a directory with a few files in it using TXS that we'll use for the initial tests.
4077 #
4078 asTestDirs = [
4079 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1'), # [0]
4080 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1'), # [1]
4081 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-1', 'subdir-1', 'subsubdir-1'), # [2]
4082 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2'), # [3]
4083 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2'), # [4]
4084 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-2', 'subdir-2', 'subsbudir-2'), # [5]
4085 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-3'), # [6]
4086 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-4'), # [7]
4087 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5'), # [8]
4088 oTestVm.pathJoin(self.oTestFiles.oRoot.sPath, 'rmtestdir-5', 'subdir-5'), # [9]
4089 ]
4090 asTestFiles = [
4091 oTestVm.pathJoin(asTestDirs[0], 'file-0'), # [0]
4092 oTestVm.pathJoin(asTestDirs[0], 'file-1'), # [1]
4093 oTestVm.pathJoin(asTestDirs[0], 'file-2'), # [2]
4094 oTestVm.pathJoin(asTestDirs[1], 'file-3'), # [3] - subdir-1
4095 oTestVm.pathJoin(asTestDirs[1], 'file-4'), # [4] - subdir-1
4096 oTestVm.pathJoin(asTestDirs[2], 'file-5'), # [5] - subsubdir-1
4097 oTestVm.pathJoin(asTestDirs[3], 'file-6'), # [6] - rmtestdir-2
4098 oTestVm.pathJoin(asTestDirs[4], 'file-7'), # [7] - subdir-2
4099 oTestVm.pathJoin(asTestDirs[5], 'file-8'), # [8] - subsubdir-2
4100 ];
4101 for sDir in asTestDirs:
4102 if oTxsSession.syncMkDir(sDir, 0o777) is not True:
4103 return reporter.error('Failed to create test dir "%s"!' % (sDir,));
4104 for sFile in asTestFiles:
4105 if oTxsSession.syncUploadString(sFile, sFile, 0o666) is not True:
4106 return reporter.error('Failed to create test file "%s"!' % (sFile,));
4107
4108 #
4109 # Tear down the directories and files.
4110 #
4111 aoTests = [
4112 # Negative tests first:
4113 tdTestRemoveFile(asTestDirs[0], fRcExpect = False),
4114 tdTestRemoveDir(asTestDirs[0], fRcExpect = False),
4115 tdTestRemoveDir(asTestFiles[0], fRcExpect = False),
4116 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-file'), fRcExpect = False),
4117 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir'), fRcExpect = False),
4118 tdTestRemoveFile(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-file'), fRcExpect = False),
4119 tdTestRemoveDir(oTestVm.pathJoin(self.oTestFiles.oEmptyDir.sPath, 'no-such-dir', 'no-subdir'), fRcExpect = False),
4120 tdTestRemoveTree(asTestDirs[0], afFlags = [], fRcExpect = False), # Only removes empty dirs, this isn't empty.
4121 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_None,], fRcExpect = False), # ditto
4122 # Empty paths:
4123 tdTestRemoveFile('', fRcExpect = False),
4124 tdTestRemoveDir('', fRcExpect = False),
4125 tdTestRemoveTree('', fRcExpect = False),
4126 # Now actually remove stuff:
4127 tdTestRemoveDir(asTestDirs[7], fRcExpect = True),
4128 tdTestRemoveFile(asTestDirs[6], fRcExpect = False),
4129 tdTestRemoveDir(asTestDirs[6], fRcExpect = True),
4130 tdTestRemoveFile(asTestFiles[0], fRcExpect = True),
4131 tdTestRemoveFile(asTestFiles[0], fRcExpect = False),
4132 # 17:
4133 tdTestRemoveTree(asTestDirs[8], fRcExpect = True), # Removes empty subdirs and leaves the dir itself.
4134 tdTestRemoveDir(asTestDirs[8], fRcExpect = True),
4135 tdTestRemoveTree(asTestDirs[3], fRcExpect = False), # Have subdirs & files,
4136 tdTestRemoveTree(asTestDirs[3], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,], fRcExpect = True),
4137 tdTestRemoveDir(asTestDirs[3], fRcExpect = True),
4138 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4139 # No error if already delete (RTDirRemoveRecursive artifact).
4140 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentAndDir,], fRcExpect = True),
4141 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon.DirectoryRemoveRecFlag_ContentOnly,],
4142 fNotExist = True, fRcExpect = True),
4143 tdTestRemoveTree(asTestDirs[0], afFlags = [vboxcon