diff --git a/.gitignore b/.gitignore
index 1d1d5f25..a592bef7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,14 @@
WebDriverAgent
-logs/*
-build-context.tar
-apps/*
-ca-cert.pem
-ca-key.pem
-configs/supervision.p12
-minicap/*
gads-project.log
+provider.log
GADS
-gads-ui/*
-
-minicap-commands-ran.zip
-
-.vscode/launch.json
+hub/gads-ui/build/*
+hub/gads-ui/node_modules
+device_*
+gads-stream.apk
+.idea
+.DS_Store
+server.crt
+server.key
+jsconfig.json
+.vscode/launch.json
\ No newline at end of file
diff --git a/common/util/archive.go b/common/util/archive.go
index ee1872a8..fa3c54bf 100644
--- a/common/util/archive.go
+++ b/common/util/archive.go
@@ -1,6 +1,7 @@
package util
import (
+ "GADS/provider/logger"
"archive/zip"
"bytes"
"fmt"
@@ -49,7 +50,7 @@ func UnzipInMemory(zipData []byte, dest string) error {
}
} else {
for _, f := range r.File {
- fmt.Printf("Unzipping %s:\n", f.Name)
+ logger.ProviderLogger.LogDebug("unzip_app", fmt.Sprintf("Unzipping %s:\n", f.Name))
rc, err := f.Open()
if err != nil {
return err
diff --git a/docs/provider.md b/docs/provider.md
index 864262a1..5a7c3e4a 100644
--- a/docs/provider.md
+++ b/docs/provider.md
@@ -25,14 +25,13 @@ Provider configuration is added through the GADS UI
## Provider data folder - optional
The provider needs a persistent folder where logs, apps and other files might be stored.
-You can skip this step and then starting the provider will look for `apps` and `logs` folders relative to the folder where the provider binary is located.
-For example if you run the provider in `/Users/shamanec/Gads-provider` then it will look for `apps` and `logs` as `/Users/shamanec/Gads-provider/apps` and `/Users/shamanec/Gads-provider/logs` respectively.
+You can skip this step and then starting the provider will create a folder named over the provider instance nickname relative to the folder where the provider binary is located.
+For example if you run the provider in `/Users/shamanec/GADS` with nickname `Provider1` then it will create `/Users/shamanec/GADS/Provider1` folder respectively and store all related data there.
If you create a specific folder and provide it on startup - then the path will be relative to it.
Refer to the `--provider-folder` flag in [Running a provider instance](#running-a-provider-instance)
1. Create a folder on your machine that will be accessible to the provider - name it any way you want.
-2. Open the newly created folder and inside create three more folders - `apps`, `logs`, `conf`
## Provider setup
### macOS
@@ -89,7 +88,7 @@ Refer to the `--provider-folder` flag in [Running a provider instance](#running-
- Execute `./GADS provider` providing the following flags:
- `--nickname=` - mandatory, this is used to get the correct provider configuration from MongoDB
- `--mongo-db=` - optional, IP address and port of the MongoDB instance (default is `localhost:27017`)
- - `--provider-folder=` - optional, folder where provider should store logs and apps and get needed files for setup. Can be 1) relative path to the folder where provider binary is located or 2) full path on the host. Default is the folder where the binary is currently located, default is `.`
+ - `--provider-folder=` - optional, folder where provider should store logs and apps and other needed files. Can be relative path to the folder where provider binary is located or full path on the host - `./test`, `.`, `./test/test1`, `/Users/shamanec/Desktop/test` are all valid. Default is the folder where the binary is currently located - `.`
- `--log-level=` - optional, how verbose should the provider logs be (default is `info`, use `debug` for more log output)
### Dependencies notes
@@ -138,7 +137,7 @@ This is an optional but a preferable step - it can make devices setup more auton
- Set it up for supervision using a new(or existing) supervision identity. You can do that for free without having a paid MDM account.
- Connect each consecutive device and supervise it using the same supervision identity.
- Export your supervision identity file and choose a password.
-- Save your new supervision identity file in the `./conf` folder as `supervision.p12`.
+- Save your new supervision identity file in the provider folder as `supervision.p12`.
**NB** You can skip supervising the devices and you should trust manually on first pair attempt by the provider but if devices are supervised in advance setup can be more autonomous.
@@ -182,17 +181,17 @@ You need a paid Apple Developer account to build and sign `WebDriverAgent` if yo
Provider logs both to local files and to MongoDB.
#### Provider logs
-Provider logs can be found in the `provider.log` file in the `/logs` folder relative to the supplied `provider-folder` flag on start.
+Provider logs can be found in the `provider.log` file in the used provider folder - default or provided by the `--provider-folder` flag.
They will also be stored in MongoDB in DB `logs` and collection corresponding to the provider nickname.
#### Device logs
-On start a log folder and file is created for each device in the `/logs` folder relative to the supplied `provider-folder` flag on start.
+On start a log folder and file is created for each device relative to the used provider folder - default or provided by the `--provider-folder` flag.
They will also be stored in MongoDB in DB `logs` and collection corresponding to the device UDID.
### Additional notes
#### Selenium Grid
Devices can be automatically connected to Selenium Grid 4 instance. You need to create the Selenium Grid hub instance yourself and then setup the provider to connect to it.
-To setup the provider download the Selenium server jar [release](https://github.com/SeleniumHQ/selenium/releases/tag/selenium-4.13.0) v4.13. Copy the downloaded jar and put it in the provider `./conf` folder.
+To setup the provider download the Selenium server jar [release](https://github.com/SeleniumHQ/selenium/releases/tag/selenium-4.13.0) v4.13. Copy the downloaded jar and put it in the provider folder.
**NOTE** Currently versions above 4.13 don't work with Appium relay nodes and I haven't tested with lower versions. Use lower versions at your own risk.
### FAQ
@@ -211,6 +210,7 @@ To setup the provider download the Selenium server jar [release](https://github.
- GADS uses `go-ios` to install and run WebDriverAgent on iOS < 17 devices on Linux/Windows
- Make sure you've properly signed and created the [WebDriverAgent](#prepare-webdriveragent-file---linux-windows) ipa/app
- Observe the provider logs - if installation is failing, you will see the full `go-ios` command used by GADS to install the prepared WebDriverAgent ipa/app. Copy the command and try to run it from terminal without the provider. Observe and debug the output.
+ - You might have to unlock your keychain, I haven't observed the need for this but it was reported - `security unlock-keychain -p yourMacPassword ~/Library/Keychains/login.keychain`
- Observe the provider logs - if running of WDA is failing, you will see the full `go-ios` command used by GADS to run the installed WebDriverAgent. Copy the command and run it from terminal without the provider. Observe and debug the output
- *[Android] I can load the device in the UI but there is no video, why?*
- First option is that `GADS-android-stream` just doesn't work on your device - unlikely
diff --git a/hub/gads-ui/src/components/DeviceControl/StreamCanvas.js b/hub/gads-ui/src/components/DeviceControl/StreamCanvas.js
index 196744a9..e6571e17 100644
--- a/hub/gads-ui/src/components/DeviceControl/StreamCanvas.js
+++ b/hub/gads-ui/src/components/DeviceControl/StreamCanvas.js
@@ -1,5 +1,5 @@
import { Auth } from "../../contexts/Auth"
-import { useContext } from "react"
+import {useContext, useEffect} from "react"
import './StreamCanvas.css'
import { Button, Divider, Grid, Stack } from "@mui/material"
import HomeIcon from '@mui/icons-material/Home';
@@ -34,6 +34,12 @@ export default function StreamCanvas({ deviceData }) {
streamUrl = `/device/${deviceData.udid}/android-stream-mjpeg`
}
+ useEffect(() => {
+ return () => {
+ window.stop()
+ }
+ }, []);
+
return (
16
-* Install Appium with `npm install -g appium`
-* Install Appium drivers
- * iOS devices - `appium driver install xcuitestdriver`
- * Android devices - `appium driver install uiautomator2`
-* Add any additional Appium dependencies like `ANDROID_HOME`(Android SDK) environment variable, Java, etc.
-
-### Android debug bridge - Android only
-* Install `adb` (Android debug bridge). It should be available in PATH so it can be directly accessed via Terminal
-
-### Trust devices to use adb - Android only
-* On each device activate `Developer options`, open them and enable `Enable USB debugging`
-* Connect each device to the host - a popup will appear on the device to pair - allow it.
-
-### Enable Developer mode - iOS 16+ devices only
-* Open Settings > Privacy & Security > Developer Mode
-* Enable the toggle
-
-### Set up go-ios - iOS only
-1. Download the latest release of [go-ios](https://github.com/danielpaulus/go-ios) and unzip it
-* On Macos - Add it to `/usr/local/bin` with `sudo cp ios /usr/local/bin` or to PATH
-* On Linux - Add it to `/usr/local/bin` with `sudo cp ios /usr/local/bin` or to PATH
-* On Windows - add it to system PATH so its available in Terminal
-
-### GADS Android stream - Android only
-1. Starting the provider will automatically download the latest GADS-stream release and put the `apk` file in the `./conf` folder. If you want to "update" it, just delete the current file and restart the provider.
-
-### Supervise devices - iOS only, optional
-**NB** You need a Mac machine to do this!
-1. Supervise your iOS devices as explained [here](#supervise-devices--ios-only)
-2. Copy your supervision certificate and add your supervision password as explained [here](#supervise-devices---ios-only)
-
-**NB** You can skip supervising the devices and you should trust manually on first pair attempt by the provider but it is preferable to have supervised the devices in advance and provided supervision file and password to make setup more autonomous.
-
-## Linux
-### Usbmuxd
-* Install usbmuxd - `sudo apt install usbmuxd`
-
-### WebDriverAgent - iOS only
-**NB** You need a Mac machine to do this!
-1. [Create](#prepare-webdriveragent-file---linux) a `WebDriverAgent.ipa` or `WebDriverAgent.app`
-2. Copy the newly created `ipa/app` in the `/conf` folder with name `WebDriverAgent.ipa` or `WebDriverAgent.app` (exact name is important)
-
-### Known limitations - iOS
-1. It is not possible to execute **driver.executeScript("mobile: startPerfRecord")** with Appium to record application performance since Xcode tools are not available.
-2. Anything else that might need Instruments and/or any other Xcode/OSX exclusive tools
-
-## macOS
-### Xcode - iOS only
-* Install latest stable Xcode release.
-* Install command line tools with `xcode-select --install`
-
-### WebDriverAgent - iOS only
-1. Download the latest release of [WebDriverAgent](https://github.com/appium/WebDriverAgent/releases)
-2. Unzip the source code in any folder.
-3. Open WebDriverAgent.xcodeproj in Xcode
-4. Select signing profiles for WebDriverAgentLib and WebDriverAgentRunner.
-5. Run the WebDriverAgentRunner with `Build > Test` on a device at least once to validate it builds and runs as expected.
-
-or
-*NB* Using my custom WebDriverAgent you can have faster tap/swipe interactions on iOS devices.
-*NB* The provider configuration should be set to use the custom WebDriverAgent in Mongo - either set it through GADS UI or using any db tool to update the provider config in Mongo for `use_custom_wda` with `true`
-1. Download the code of the `main` branch from my fork of [WebDriverAgent](https://github.com/shamanec/WebDriverAgent)
-2. Unzip the code in any folder.
-3. Open WebDriverAgent.xcodeproj in Xcode
-4. Select signing profiles for WebDriverAgentLib and WebDriverAgentRunner.
-5. Run the WebDriverAgentRunner with `Build > Test` on a device at least once to validate it builds and runs as expected.
-
-## Windows
-### iTunes - iOS only
-* Install `iTunes` to be able to provision iOS < 17 devices
-
-# Configuration setup
-The provider can be initialy set up or updated via the GADS UI.
-
-## Common
-### Devices config
-No configuration needed, at the moment the provider will attempt to provision every device connected to it.
-
-### Selenium Grid
-Devices can be automatically connected to Selenium Grid 4 instance. You need to create the Selenium Grid hub instance yourself and then setup the provider to connect to it.
-To setup the provider download the Selenium server jar [release](https://github.com/SeleniumHQ/selenium/releases/tag/selenium-4.13.0) v4.13. Copy the downloaded jar and put it in the provider `./conf` folder.
-**NOTE** Currently versions above 4.13 don't work with Appium relay nodes and I haven't tested with lower versions. Use lower versions at your own risk.
-
-# Additional setup notes
-## Prepare WebDriverAgent file - Linux, Windows
-You need a Mac machine to at least build and sign WebDriverAgent, currently we cannot avoid this.
-You need a paid Apple Developer account to build and sign `WebDriverAgent`. With latest Apple changes it might be possible to do it with free accounts but maybe you'll have to sign the `ipa` file each week and other limitations might apply as well
-
-1. Download and install [iOS App Signer](https://dantheman827.github.io/ios-app-signer/)
-2. Download the code of the lates mainstream [WebDriverAgent](https://github.com/appium/WebDriverAgent/releases) release or alternatively the code from the `main` branch of my fork of [WebDriverAgent](https://github.com/shamanec/WebDriverAgent) for faster tap/swipe interactions.
-2. Open `WebDriverAgent.xcodeproj` in Xcode.
-3. Ensure a team is selected before building the application. To do this go to: *Targets* and select each target one at a time. There should be a field for assigning teams certificates to the target.
-4. Remove your `WebDriverAgent` folder from `DerivedData` and run `Clean build folder` (just in case)
-5. Next build the application by selecting the `WebDriverAgentRunner` target and build for `Generic iOS Device`. Run `Product => Build for testing`. This will create a `Products/Debug-iphoneos` folder in the specified project directory.
- `Example`: **/Users//Library/Developer/Xcode/DerivedData/WebDriverAgent-dzxbpamuepiwamhdbyvyfkbecyer/Build/Products/Debug-iphoneos**
-6. Open `iOS App Signer`
-7. Select `WebDriverAgentRunner-Runner.app`.
-8. Generate the WebDriverAgent *.ipa file.
-
-Alternatively:
-7. Copy the `WebDriverAgentRunner-Runner.app` instead of bundling to IPA. `go-ios` allows us to install `app` as well as `ipa` so this might be less painful.
-
-## Supervise the iOS devices - Linux, macOS, Windows - optional
-This is a non-mandatory but a preferable step - it will reduce the needed device provisioning manual interactions
-1. Install Apple Configurator 2 on your Mac.
-2. Attach your first device.
-3. Set it up for supervision using a new(or existing) supervision identity. You can do that for free without having a paid MDM account.
-4. Connect each consecutive device and supervise it using the same supervision identity.
-5. Export your supervision identity file and choose a password.
-6. Save your new supervision identity file in the project `./conf` folder as `supervision.p12`.
-
-**Note** You can also `Trust` manually when connecting a device, might be required again after host/device restart.
-
-[] TODO - see if supervising can be automated with `go-ios` to skip this step and make set up more autonomous
-
-# Running the provider
-## Prebuilt binary
-1. Download the prebuilt binary for your OS from the releases
-
-## Build from source
-1. Clone the project
-2. Execute `go build .`
-
-## Start the provider
-1. Execute `./GADS-devices-provider` providing the flags:
- a. `--nickname=` - this is used to get the correct provider configuration from MongoDB
- b. `--mongo-db=` - address and port of the MongoDB instance
- c. `--provider-folder=` - optional, folder where provider should store logs and apps and get needed files for setup. Can be 1) relative path to the folder where provider binary is located or 2) full path on the host. Default is the folder where the binary is currently located
- d. `--log-level=` - optional, how verbose should the provider logs be, use `debug` for more verbose output, default is `info`
-
-Example default path: `./GADS-devices-provider --nickname=Provider1 --mongo-db=192.168.1.6:27017`
-Example relative path: `./GADS-devices-provider --nickname=Provider1 --mongo-db=192.168.1.6:27017 --provider-folder==./provider-data --log-level=debug`
-Example full path: `./GADS-devices-provider --nickname=Provider1 --mongo-db=192.168.1.6:27017 --provider-folder==/Users/shamanec/provider-data --log-level=debug`
-
-On start the provider will connect to MongoDB and read its respective configuration data.
-
-# Logging
-Provider logs both to local files and in MongoDB.
-
-## Provider logs
-Provider logs can be found in the `provider.log` file in the `/logs` folder relative to the supplied `provider-folder` flag on start. They will also be in MongoDB in DB `logs` and collection corresponding to the provider name.
-
-## Device logs
-On start a log folder and file is created for each device in the `/logs` folder relative to the supplied `provider-folder` flag on start. They will also be in MongoDB in DB `logs` and collection corresponding to the device UDID.
diff --git a/provider/logger/logger.go b/provider/logger/logger.go
index 514a044b..353723b8 100644
--- a/provider/logger/logger.go
+++ b/provider/logger/logger.go
@@ -31,8 +31,8 @@ func SetupLogging(level string) {
logLevel = level
var err error
- fmt.Println(fmt.Sprintf("%s/logs/provider.log", config.Config.EnvConfig.ProviderFolder))
- ProviderLogger, err = CreateCustomLogger(fmt.Sprintf("%s/logs/provider.log", config.Config.EnvConfig.ProviderFolder), config.Config.EnvConfig.Nickname)
+ fmt.Println(fmt.Sprintf("Provider will be logging to `%s/provider.log`", config.Config.EnvConfig.ProviderFolder))
+ ProviderLogger, err = CreateCustomLogger(fmt.Sprintf("%s/provider.log", config.Config.EnvConfig.ProviderFolder), config.Config.EnvConfig.Nickname)
if err != nil {
log.Fatalf("Failed to create custom logger for the provider instance - %s", err)
}
diff --git a/provider/provider.go b/provider/provider.go
index dba69ef9..60601b7d 100644
--- a/provider/provider.go
+++ b/provider/provider.go
@@ -32,8 +32,18 @@ func StartProvider(flags *pflag.FlagSet) {
log.Fatalf("Please provide valid provider instance nickname via the --nickname flag, e.g. --nickname=Provider1")
}
+ if providerFolder == "." {
+ providerFolder = fmt.Sprintf("./%s", nickname)
+ }
+
fmt.Println("Preparing...")
+ // Create the provider folder if needed
+ err := os.MkdirAll(providerFolder, os.ModePerm)
+ if err != nil {
+ log.Fatalf("Failed to create provider folder `%s` - %s", providerFolder, err)
+ }
+
// Create a connection to Mongo
db.InitMongoClient(mongoDb)
defer db.MongoCtxCancel()
@@ -43,13 +53,6 @@ func StartProvider(flags *pflag.FlagSet) {
// Defer closing the Mongo connection on provider stopped
defer db.CloseMongoConn()
- // Check if logs folder exists in given provider folder and attempt to create it if it doesn't exist
- createFolderIfNotExist(providerFolder, "logs")
- // Check if conf folder exists in given provider folder and attempt to create it if it doesn't exist
- createFolderIfNotExist(providerFolder, "conf")
- // Check if apps folder exists in given provider folder and attempt to create it if it doesn't exist
- createFolderIfNotExist(providerFolder, "apps")
-
// Setup logging for the provider itself
logger.SetupLogging(logLevel)
logger.ProviderLogger.LogInfo("provider_setup", fmt.Sprintf("Starting provider on port `%v`", config.Config.EnvConfig.Port))
@@ -128,7 +131,7 @@ func StartProvider(flags *pflag.FlagSet) {
go devices.Listener()
// Start the provider server
- err := startHTTPServer()
+ err = startHTTPServer()
if err != nil {
log.Fatal("HTTP server stopped")
}
@@ -165,7 +168,7 @@ func createFolderIfNotExist(baseFolder, subFolder string) {
// Check for and set up selenium jar file for creating Appium grid nodes in config
func configureSeleniumSettings() {
seleniumJarFile := ""
- err := filepath.Walk(fmt.Sprintf("%s/conf", config.Config.EnvConfig.ProviderFolder), func(path string, info os.FileInfo, err error) error {
+ err := filepath.Walk(fmt.Sprintf("%s/", config.Config.EnvConfig.ProviderFolder), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
@@ -187,10 +190,10 @@ func configureSeleniumSettings() {
// Check for and set up WebDriverAgent.ipa/app binary in config
func configureWebDriverBinary(providerFolder string) error {
// Check for WDA ipa, then WDA app availability
- ipaPath := fmt.Sprintf("%s/conf/WebDriverAgent.ipa", providerFolder)
+ ipaPath := fmt.Sprintf("%s/WebDriverAgent.ipa", providerFolder)
_, err := os.Stat(ipaPath)
if err != nil {
- appPath := fmt.Sprintf("%s/conf/WebDriverAgent.app", providerFolder)
+ appPath := fmt.Sprintf("%s/WebDriverAgent.app", providerFolder)
_, err = os.Stat(appPath)
if os.IsNotExist(err) {
return err
diff --git a/provider/providerutil/providerutil.go b/provider/providerutil/providerutil.go
index f70b1c3d..dedd6b60 100644
--- a/provider/providerutil/providerutil.go
+++ b/provider/providerutil/providerutil.go
@@ -165,7 +165,7 @@ func CheckGadsStreamAndDownload() error {
// Check if the gads-stream.apk file is located in the provider `conf` folder
func isGadsStreamApkAvailable() bool {
- _, err := os.Stat(fmt.Sprintf("%s/conf/gads-stream.apk", config.Config.EnvConfig.ProviderFolder))
+ _, err := os.Stat(fmt.Sprintf("%s/gads-stream.apk", config.Config.EnvConfig.ProviderFolder))
if os.IsNotExist(err) {
return false
}
@@ -175,9 +175,9 @@ func isGadsStreamApkAvailable() bool {
// Download the latest release of GADS-Android-stream and put the apk in the provider `conf` folder
func downloadGadsStreamApk() error {
logger.ProviderLogger.LogInfo("provider", "Downloading latest GADS-stream release apk file")
- outFile, err := os.Create(fmt.Sprintf("%s/conf/gads-stream.apk", config.Config.EnvConfig.ProviderFolder))
+ outFile, err := os.Create(fmt.Sprintf("%s/gads-stream.apk", config.Config.EnvConfig.ProviderFolder))
if err != nil {
- return fmt.Errorf("Could not create file at %s/conf/gads-stream.apk - %s", config.Config.EnvConfig.ProviderFolder, err)
+ return fmt.Errorf("Could not create file at %s/gads-stream.apk - %s", config.Config.EnvConfig.ProviderFolder, err)
}
defer outFile.Close()
@@ -206,26 +206,3 @@ func downloadGadsStreamApk() error {
return nil
}
-
-func GetAllAppFiles() []string {
- file, err := os.Open(fmt.Sprintf("%s/apps", config.Config.EnvConfig.ProviderFolder))
- if err != nil {
- logger.ProviderLogger.LogError("provider", fmt.Sprintf("Could not os.Open() apps directory - %s", err))
- return []string{}
- }
- defer file.Close()
-
- fileList, err := file.Readdir(-1)
- if err != nil {
- logger.ProviderLogger.LogError("provider", fmt.Sprintf("Could not Readdir on the apps directory - %s", err))
- return []string{}
- }
-
- var files []string
- for _, file := range fileList {
- files = append(files, file.Name())
- fmt.Println(file.Size())
- }
-
- return files
-}
diff --git a/provider/router/routes.go b/provider/router/routes.go
index dfa4055c..52b59723 100644
--- a/provider/router/routes.go
+++ b/provider/router/routes.go
@@ -70,7 +70,7 @@ func newAppiumProxy(target string, path string) *httputil.ReverseProxy {
func UploadAndInstallApp(c *gin.Context) {
// Specify the upload directory
- uploadDir := fmt.Sprintf("%s/apps/", config.Config.EnvConfig.ProviderFolder)
+ uploadDir := fmt.Sprintf("%s/", config.Config.EnvConfig.ProviderFolder)
// Read the file from the form data
file, err := c.FormFile("file")