VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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

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