VirtualBox

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

Last change on this file since 103219 was 103219, checked in by vboxsync, 11 months ago

Validation Kit/tdAddGuestCtrl.py: Fixed session 0 checks. bugref:10586

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

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