├── .gitignore ├── ADDITIONAL_FEATURES.md ├── CHANGELOG ├── INSTALLATION.md ├── LICENSE ├── README.md ├── XVFB_ACCELERATION.md ├── binaries ├── 32bit │ ├── libinterface.dll │ ├── libinterface.so │ ├── libmkv.dll │ ├── libmkv.so │ ├── libvpx.dll │ ├── libvpx.so │ ├── libx11_screenshot_source.so │ ├── libxvfb_interface.so │ ├── libyuv.dll │ └── libyuv.so └── 64bit │ ├── libinterface.dll │ ├── libinterface.dylib │ ├── libinterface.so │ ├── libmkv.dll │ ├── libmkv.dylib │ ├── libmkv.so │ ├── libvpx.dll │ ├── libvpx.dylib │ ├── libvpx.so │ ├── libx11_screenshot_source.so │ ├── libxvfb_interface.so │ ├── libyuv.dll │ ├── libyuv.dylib │ └── libyuv.so ├── node-test.py ├── pom.xml └── src ├── main ├── assembly │ └── native-zip.xml ├── c │ ├── encoder_interface.c │ ├── encoder_test.c │ ├── x11_screenshot_source.c │ └── xvfb_interface.c └── java │ └── com │ └── aimmac23 │ ├── exception │ └── MissingFrameException.java │ ├── http │ └── HttpClientFactory.java │ ├── hub │ ├── HubVideoRegistry.java │ ├── proxy │ │ ├── RegistrationRequestCorrector.java │ │ └── VideoProxy.java │ ├── servlet │ │ ├── AbstractHubVideoServlet.java │ │ ├── HubVideoDownloadServlet.java │ │ └── HubVideoInfoServlet.java │ └── videostorage │ │ ├── BasicWebDAVStore.java │ │ ├── CloudS3StoredVideoInfoContext.java │ │ ├── CloudS3VideoDownloadContext.java │ │ ├── CloudS3VideoStore.java │ │ ├── IVideoStore.java │ │ ├── LocalFileVideoStore.java │ │ ├── LocalTempFileStore.java │ │ ├── LocationAwareS3Object.java │ │ ├── SessionInfoBean.java │ │ ├── StoredVideoDownloadContext.java │ │ └── StoredVideoInfoContext.java │ └── node │ ├── RecordVideoCallable.java │ ├── RobotScreenshotSource.java │ ├── ScreenshotSource.java │ ├── VideoRecordController.java │ ├── X11ScreenshotSource.java │ ├── XvfbFileScreenshotSource.java │ ├── args │ ├── IRecordArgs.java │ └── SystemPropertyRecordArgs.java │ ├── jna │ ├── EncoderInterface.java │ ├── JnaLibraryLoader.java │ ├── LibMKV.java │ ├── LibVPX.java │ ├── X11ScreenshotSource.java │ ├── XvfbScreenshotInterface.java │ └── YUVLib.java │ └── servlet │ └── VideoRecordingControlServlet.java └── test ├── java └── com │ └── aimmac23 │ ├── hub │ ├── HubProxyIntegrationTest.java │ ├── HubServletIntegrationTest.java │ ├── VideoDownloadTests.java │ └── examples │ │ ├── AbstractVideoSeleniumTest.java │ │ └── ExampleSeleniumTests.java │ └── node │ ├── DummyEncoderInterface.java │ ├── TestScreenshotSource.java │ ├── VideoRecordControllerTest.java │ └── jna │ └── VideoEncoderTest.java └── resources └── logback.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | target 5 | native.zip 6 | -------------------------------------------------------------------------------- /ADDITIONAL_FEATURES.md: -------------------------------------------------------------------------------- 1 | Additional Features 2 | =================== 3 | 4 | # Video Node Arguments 5 | 6 | ## Custom Framerate 7 | 8 | -Dvideo.framerate= 9 | 10 | Sets the framerate that we try to record video at - default value is "15" frames a second. 11 | 12 | Selecting higher values has no harmful side-effects (apart from not getting the requested framerate), while selecting lower values will consume less CPU time. 13 | 14 | ## Xvfb Acceleration (Linux/Unix only) 15 | 16 | Xvfb is a virtual display on Linux/Unix systems, which only renders the screen in memory (so no graphics cards/monitors are involved). With some additional configuration we can use some Xvfb features to improve video performance - see [Xvfb Acceleration](XVFB_ACCELERATION.md) on how to configure it. 17 | 18 | ## X11 Acceleration (Linux/Unix only) 19 | 20 | As of version 2.3 we can use some simplified screenshot code to grab the screen image (currently off by default). To use this, pass this option to the node: 21 | 22 | -Dvideo.source=X11 23 | 24 | You should then see the node print this at startup: 25 | 26 | Using X11 Native Screenshot Source 27 | 28 | # Hub Arguments 29 | 30 | ## Video Storage Arguments 31 | 32 | The Hub supports an extensible plugin system to decide how to store the recorded videos. 33 | 34 | -Dvideo.storage= 35 | 36 | Changes the backend implementation for how we store videos. This can be either a plugin provided by this project, or a user-defined plugin on the classpath. 37 | 38 | ### com.aimmac23.hub.videostorage.LocalTempFileStore (default) 39 | 40 | This implementation stores the videos as temporary files, and deletes them if too many accumulate (maximum of 200 videos). It also tends to forget about currently stored videos if the hub gets restarted. 41 | 42 | There are currently no configurable options for this plugin. 43 | 44 | ### com.aimmac23.hub.videostorage.LocalFileVideoStore 45 | 46 | Stores videos in a directory on disk. Videos persist over Hub restarts, and are never deleted. Note that clients can request any file in the configured directory, so be aware of where they are stored. 47 | 48 | -Dvideo.path= 49 | 50 | Uses the given directory to store the videos. 51 | 52 | ### com.aimmac23.hub.videostorage.BasicWebDAVStore 53 | 54 | Uploads videos to a server which supports WebDAV. Following HTTP redirects when uploading is not supported. 55 | 56 | -Dwebdav.url= 57 | 58 | The URL can be either start with http:// or https://. 59 | 60 | -Dwebdav.username= 61 | 62 | Optionally provide a username to use when uploading the video. 63 | 64 | -Dwebdav.password= 65 | 66 | Optionally provide a password to use when uploading the video. 67 | 68 | ### com.aimmac23.hub.videostorage.CloudS3VideoStore 69 | 70 | Uploads videos to [Amazon Simple Cloud Storage](https://aws.amazon.com/s3). Note that the uploaded videos are set to be publicly-readable, unless the AWS bucket has more specific access control permissions applied. 71 | 72 | To use this storage you will need to create an S3 bucket and a set of [IAM credentials](https://aws.amazon.com/iam/) to be able to upload files to it. 73 | 74 | After that just configure these environment variables 75 | 76 | ```shell 77 | AWS_BUCKET_NAME: The S3 bucket name where you want to upload the videos 78 | AWS_REGION: The S3 region where you've created your bucket. Note that if you are using the default region this must be set to "us-east-1". 79 | AWS_ACCESS_KEY_ID: IAM credential access key id 80 | AWS_SECRET_ACCESS_KEY: IAM credential secret access key 81 | ``` 82 | 83 | After a video has been uploaded you can use the [Hub Video info servlet](#hub-video-information-servlet) to obtain its URL on S3. 84 | 85 | ### User-Defined plugin 86 | 87 | You can also create your own plugin to handle storage, but it has to implement com.aimmac23.hub.videostorage.IVideoStore. 88 | 89 | ## Miscellaneous Arguments 90 | 91 | Sometimes the Hub will tell the test that the Session has been successfully closed slightly before it has finished copying the video off the node. If this has occurred, then the Hub will make any video download calls wait up to 20 seconds (by default) for the copying to finish. To control the time, set: 92 | 93 | -Dvideo.downloadTimeout= 94 | 95 | ## Hub Video information servlet 96 | 97 | The hub can also include information about the videos it is currently storing (such as the location), in case links to the videos need to be included in something else, such as a test report. 98 | 99 | To use this, add another servlet to the hub: 100 | 101 | -servlets com.aimmac23.hub.servlet.HubVideoDownloadServlet,com.aimmac23.hub.servlet.HubVideoInfoServlet 102 | 103 | You can then ask the Hub for information about videos it knows about: 104 | 105 | http://127.0.0.1:4444/grid/admin/HubVideoInfoServlet/?sessionId=14da5f32-5556-4003-bf62-da0ae7653358 106 | 107 | And the hub will reply with a JSON response. This example uses the LOCAL_FILE video storage. 108 | 109 | { 110 | "additional": {"path": "/tmp/videos/14da5f32-5556-4003-bf62-da0ae7653358.webm"}, 111 | "fileSize": 279497, 112 | "storageType": "LOCAL_FILE" 113 | } 114 | 115 | An example of a response if using [S3](#com.aimmac23.hub.videostorage.CloudS3VideoStore): 116 | 117 | { 118 | "additional": {"path": "https://s3.amazonaws.com/selenium-grid-videos/14da5f32-5556-4003-bf62-da0ae7653358.webm"}, 119 | "fileSize": 279497, 120 | "storageType": "CLOUD_AWS_S3" 121 | } 122 | 123 | To get file path information in the response, you will need to configure a video storage provider - see "Video Storage Arguments" above. 124 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Version 2.9 12/07/2019 2 | ====================== 3 | 4 | * Updates to project dependencies, to handle upstream Selenium project changes (contributed by https://github.com/DeathBeforeDecaf) 5 | * Bundle Apache HTTP client and commons-logging, since Selenium no longer depends on these projects. 6 | 7 | Version 2.8 14/08/2018 8 | ====================== 9 | * Update to fix compile errors when running against newer versions of Guava (related to the Files.fileTreeTraverser() API) 10 | 11 | Version 2.7 08/04/2018 12 | ======================= 13 | * Add JMX annotations, so the VideoProxy still works under Selenium 3.9.0 14 | 15 | Version 2.6 19/11/2017 16 | ====================== 17 | 18 | * Update project to build against upstream code changes - Selenium 3.7.1 now required (Use version 2.5 for Selenium 3.6.0 and below). 19 | * Expand unit test coverage for hub proxy 20 | 21 | Version 2.5 11/11/2017 22 | ====================== 23 | 24 | * Bump build to Java 8 bytecode 25 | * Refactor to make unit testing easier 26 | * Add some unit tests 27 | * Fix rounding bug in FPS calculations 28 | * Bundle JNA dependencies in JAR file - recent versions of Selenium no longer use this 29 | 30 | Version 2.4 01/10/2017 31 | ====================== 32 | 33 | * Update version dependencies a bit (contributed by saikek) 34 | * Add AWS video upload support (contributed by ovidiubute) 35 | 36 | Version 2.3 26/02/2017 37 | ====================== 38 | 39 | * Fix failure introduced by Selenium 3.1 in the capabilities setting code (issue #27, issue #35) 40 | * Greatly improve X11 screenshot performance by writing a greatly simplified version of the AWT Robot code (issue #14) 41 | This is off by default for now, but can be enabled in Linux/Unix by passing "-Dvideo.source=x11" to the JVM 42 | 43 | Version 2.2 01/01/2017 44 | ======================= 45 | 46 | * Re-add support for Selenium V2, by using Java reflection to smooth over incompatible changes (issue #27) 47 | 48 | Version 2.1 01/11/2016 49 | ======================= 50 | 51 | * Properly fix issue #23, where JNA was picking up the system version of libvpx on Linux, causing the JVM to segfault. 52 | 53 | Version 2.0 01/11/2016 54 | ======================= 55 | 56 | * Update build to support Selenium 3 (contributed by mhardin) 57 | 58 | Version 1.9 23/12/2015 59 | ====================== 60 | 61 | * Recompile 32-bit Windows native dependencies, to fix problem where they were dynamically linked against GCC's libc library (issue #19) 62 | * Commit fix for issue #5 (where the node can get into an inconsistent recording state if the hub gets restarted) 63 | * Logging/documentation improvements 64 | 65 | Version 1.8 26/06/2015 66 | ====================== 67 | 68 | * A lot of POM changes to upload this project to Maven central (no code changes) 69 | * Fix issue where the native code zip file was being included in the source JAR file 70 | 71 | Version 1.7 12/02/2014 72 | ====================== 73 | 74 | * Fix for issue where dynamically changing resolution before recording a test didn't record at the new resolution - we used the 75 | resolution at startup (fix contributed by https://github.com/suayipozmen) 76 | 77 | Version 1.6 05/02/2014 78 | ====================== 79 | 80 | * Fix issue #10 - make video download requests wait until the Hub has retrieved the video from the Node 81 | 82 | 83 | Version 1.5 22/11/2014 84 | ====================== 85 | 86 | * Bundled the org.json:json Maven artifact, so we can parse JSON from Selenium 2.44 onwards - they dropped it as a dependency (issue #9) 87 | * Fix integer promotion bug in the xvfb acceleration code, which allows us to record in larger resolutions (fix contributed by https://github.com/DeathBeforeDecaf) 88 | * Bump Selenium version we are compiling against to 2.43 (shouldn't make any difference) 89 | 90 | Version 1.4 21/11/2014 91 | ====================== 92 | 93 | * Add pre-compiled and tested binaries for 32-bit Windows 94 | * Add check in Java code to make sure we are taking screenshots with the correct bit depth 95 | 96 | Version 1.3 11/09/2014 97 | ====================== 98 | 99 | * Make the node delete extracted native dependencies and recorded videos on exit (fixes issue #7). 100 | This could cause the machine the node was running on to diskfill if the node was repeatedly restarted. 101 | 102 | Version 1.2 15/08/2014 103 | ====================== 104 | 105 | * Add a new means of taking screenshots for Xvfb, where we can memory-map the Xvfb output into our address space to run the video encoder directly on. 106 | Note that this requires an extra JVM flag to make this work. 107 | * Check that the video data source is sane on startup, instead of when we first record a video. 108 | 109 | Version 1.1 8/07/2014 110 | ===================== 111 | 112 | * Add an API call to the Node to reset the video recording to a known state (will be used in future releases) 113 | * Fix some resource leaks in Video Download/Info servlets (issue #4) 114 | 115 | Version 1.0 1/07/2014 116 | ===================== 117 | 118 | * Bump to release version (no code changes) 119 | 120 | Version 0.11 29/06/2014 121 | ======================= 122 | 123 | * Handle native code error conditions better (but haven't managed to test it because it works perfectly :/) 124 | * Tweak the IVideoStore interface again to also pass in the video content length (in bytes) 125 | * Reduce the excess video recording time when closing the session to be 1/2 a second (was 1 second) 126 | * Plug a security hole which existed in most of the video storage mechanisms by which a request could access any file ending in .webm off the filesystem. 127 | 128 | Version 0.10 25/06/2014 129 | ======================= 130 | 131 | * Fix an issue where HTTP connections leaked, and we couldn't acquire any more 132 | * Change the native code extraction logic to only happen once at startup (previously we also did it when recording a video too) 133 | * Bump the default framerate to 15 - some platforms can record faster than others. 134 | 135 | Version 0.9 24/06/2014 136 | ====================== 137 | 138 | * Recompiled Windows x86_64 binaries to fix video length bug (Issue #3) 139 | * Changed the interface for IVideoStore to be a bit cleaner 140 | 141 | Version 0.8 23/06/2014 142 | ====================== 143 | 144 | * Added pre-compiled binaries for OS X 145 | * Added pre-compiled binaries for Linux x86 (32-bit) 146 | * Recompiled all binaries (except Windows x86_64) to fix video length bug (Issue #3) 147 | * Change the API for IVideoStore to also include requested capabilities + node capabilities when storing the job. This is intended 148 | for use when integrating with custom job reporting code. 149 | * Renames packages/POM from 'com.mooo.aimmac23' -> 'com.aimmac23' 150 | * Removed experimental support for Windows x86 (32-bit). 64-bit binaries compiled by the same process crashed, so these probably won't work either. 151 | 152 | Version 0.7 20/06/2014 153 | ====================== 154 | 155 | * Added experimental support for Windows x86 (32-bit). I don't have a 32-bit JVM on-hand to test that the native code works. 156 | * Wrote a plugin to make how we store videos be extensible 157 | * LocalTempFileStore - the pre-existing storage mechanism 158 | * LocalFileVideoStore - permanent storage in a directory 159 | * BasicWebDAVStore - permanent storage in a WebDAV directory on a webserver 160 | * Added HubVideoInfoServlet to provide storage-plugin specific information about where a video is kept 161 | 162 | Version 0.6 26/05/2014 163 | ====================== 164 | 165 | * Fixed an issue where videos were not immediately available after the session was closed - only after the Hub had finished tidying up the node. We now immediately transfer the video to the Hub. 166 | 167 | Version 0.5 03/05/2014 168 | ====================== 169 | 170 | * Make the target framerate be configurable 171 | * Fix a playback framerate issue when the video wasn't recorded fast enough (was playing too fast) 172 | * Recompile binaries on glibc 2.13, because not all Linux installations have 2.17 173 | 174 | Version 0.4 21/04/2014 175 | ====================== 176 | 177 | * Commit some pre-built linux binaries to Git. 178 | * Make Maven assemble the native code zip file. 179 | * Added support for Windows x86_64 - committed some binaries for it (details on wiki). Note that this requires a 64 bit JVM to work. 180 | 181 | Version 0.3 18/04/2014 182 | ====================== 183 | 184 | * Move the compiled MKV encoder code out into its own library, where it should be. 185 | * Fix C memory leak by actually freeing up memory. 186 | 187 | 188 | Version 0.2 15/04/2014 189 | ====================== 190 | 191 | Convert project to use a WebM/VP8 encoder - we now use JNA to run the encoder, with a C implementation to abstract away the complicated C data structures. 192 | 193 | * Higher framerates achieved 194 | * Capped framerate at 8 fps, slightly slower than the maximum speed, due to continuing time-base issues 195 | * Implementation now restricted to Linux-only. 196 | 197 | 198 | Version 0.1 08/04/2014n 199 | ====================== 200 | 201 | Initial implementation. Used a Java implementation of an h264 encoder. It centralized videos on the Hub using some download servlets, and allowed the user to get the video. 202 | 203 | * The encoder wasn't very fast (~4 fps, with the Java Robot taking screenshots) 204 | * The videos generated were massive 205 | * Some time-base issues 206 | * Some browsers/players refused to play back the video 207 | * Patent issues for encoding h264 208 | 209 | -------------------------------------------------------------------------------- /INSTALLATION.md: -------------------------------------------------------------------------------- 1 | 2 | Installation 3 | ============ 4 | 5 | This guide assumes some familiarity with the Selenium Grid setup guide: https://code.google.com/p/selenium/wiki/Grid2 6 | 7 | Download: 8 | * The latest "selenium-server-standalone" JAR from http://selenium-release.storage.googleapis.com/index.html 9 | * The latest "selenium-video-node" JAR from http://repo1.maven.org/maven2/com/aimmac23/selenium-video-node/ 10 | 11 | ### Node setup 12 | 13 | A Selenium node can be launched by running: 14 | 15 | java -cp selenium-video-node-2.9.jar:selenium-server-standalone-3.141.59.jar org.openqa.grid.selenium.GridLauncherV3 -servlets com.aimmac23.node.servlet.VideoRecordingControlServlet -proxy com.aimmac23.hub.proxy.VideoProxy -role wd 16 | 17 | Note that on Windows, the classpath seperator (for the -cp argument) is ";" instead of ":" - Java will not report incorrect usage as an error, but you will get ClassNotFound exceptions. 18 | 19 | If you are running this under Linux, then it may be convenient to run the Video Node under a virtual X server, so the real X server can be used for other purposes: 20 | 21 | xvfb-run -a -s "-screen 0 1280x1024x24 -wr"