2

Here is my scenario:

we run our selenium test suite on selenium grid which was setup in docker containers(linux box) from jenkins.

In one of my test when i click on export option, it downloads an excel file on selenium grid.

Issue:

I am unable to find the location of the downloaded file(everytime test may run in different nodes in selenium grid).

what i am expecting:

Can someone help me, how to find the location of the file and i think i cannot open an excel file in linux box so if i can move that file to one of SFTP location then i can connect to SFTP and can read the content in it for validation.

Thanks

nurav
  • 269
  • 2
  • 6
  • 19

4 Answers4

2

Assumptions :

  • Since you mentioned you are using Docker and since there is currently no Docker images for either Windows (or) OSX, your browser is either Chrome or Firefox
  • You are using a technique such as this to configure the default download location for your Chrome or Firefox browser.

You would first need to figure out to which node did your Grid route your test execution to. For doing that, you would employ a technique such as below to retrieve this information (I originally posted this as a gist here, then wrote up a blog about this here and finally built a library called talk2Grid which provides this capability out of the box without you having to write any extra amount of code)

public class GridInfoExtracter {

 private static String[] getHostNameAndPort(String hostName, int port,
  SessionId session) {
  String[] hostAndPort = new String[2];
  String errorMsg = "Failed to acquire remote webdriver node and port info. Root cause: ";

  try {
   HttpHost host = new HttpHost(hostName, port);
   DefaultHttpClient client = new DefaultHttpClient();
   URL sessionURL = new URL("http://" + hostName + ":" + port + "/grid/api/testsession?session=" + session);
   BasicHttpEntityEnclosingRequest r = new BasicHttpEntityEnclosingRequest("POST", sessionURL.toExternalForm());
   HttpResponse response = client.execute(host, r);
   JSONObject object = extractObject(response);
   URL myURL = new URL(object.getString("proxyId"));
   if ((myURL.getHost() != null) && (myURL.getPort() != -1)) {
    hostAndPort[0] = myURL.getHost();
    hostAndPort[1] = Integer.toString(myURL.getPort());
   }
  } catch (Exception e) {
   logger.log(Level.SEVERE, errorMsg, e);
   throw new RuntimeException(errorMsg, e);
  }
  return hostAndPort;
 }

 private static JSONObject extractObject(HttpResponse resp) throws IOException, JSONException {
  BufferedReader rd = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));
  StringBuffer s = new StringBuffer();
  String line;
  while ((line = rd.readLine()) != null) {
   s.append(line);
  }
  rd.close();
  JSONObject objToReturn = new JSONObject(s.toString());
  return objToReturn;
 }
}

Now you would have the IP and port information of the Docker node on which your test is running.

You now have two options:

  1. You download the file from the docker container using scp (or)
  2. You build a custom servlet and then inject it into the node as explained here. Then you make a http connection to this node by hitting your servlet and then download the file to your local machine. The node's IP and port are anyway available to you from your session.

That should help you with this.

All said and done you might also want to read this blog that Mark Collins created which talks about why you should not be trying to download files and if at all there's a need, what is the right way of doing it.

Krishnan Mahadevan
  • 14,121
  • 6
  • 34
  • 66
  • Thanks much for the info. I did use the code and figured out where my test where was routing to "Session a8880149-f0f4-4a33-ab5e-8296564ea087 was routed to **GridNode [IP='172.17.0.7', Port=5555]**". But i couldn't figure where exactly the file is getting download on the grid or on which docker container. Any idea where would be the default download location for a remote webdriver – nurav Jun 29 '17 at 20:16
  • There's no default location for the file download that webdriver decides. Its always the browser that defaults to some location. In my answer I have provided links to articles that show you how to control the location as well. So you could employ that to force the browser to download to your choice of location and then get it from there. If my answer has helped, I would request you to please help accept it. – Krishnan Mahadevan Jul 03 '17 at 02:25
1

By way of an update as this is now quite an old question see the following information on selenium.dev that describes the Grid endpoint that GET's a downloaded file. Thanks to @krishnan-mahadevan for the solution. https://www.selenium.dev/documentation/grid/configuration/cli_options/#specifying-path-from-where-downloaded-files-can-be-retrieved

mactwixs
  • 402
  • 1
  • 6
  • 15
0

Thought of sharing the approach to check that the file is downloaded into specific location in selenium grid node (download location need to be specified in chrome options or firefox profile) and checking file is present in specified download directory:

(Written code in python)

Passing download directory and downloaed file name, for example, I have set C:\File_Download as my download directory and capturing downloaded filename from application and checking same file downloaded:

Note: Used robot framework builtin library to get session id, SSH to connect to remote machines and created selenium grid nodes in remote machines.

 import requests, json
 from robot.libraries.BuiltIn import BuiltIn
 import paramiko

 def check_downloaded_file_present_in_remote_machine(dir_location, filename):
    session_id = BuiltIn().get_library_instance('SeleniumLibrary')._current_browser().session_id
    response = requests.get("http://{SeleniumHubIP}:{port}/grid/api/testsession?",params= 
   {'session':session_id})
   json_resp = response.json()
    ip_addr = json_resp['proxyId'].split('://')[1].split(':')[0]
    print ip_addr
    client = paramiko.SSHClient()
    client.load_host_keys('{home\user_directory}\.ssh\known_hosts')
    client.connect(hostname=ip_addr,port=22,username='XXXXX',password='XXXX',look_for_keys=True)
    stdin, stdout, stderr = client.exec_command('cd ' +dir_location+' && ls')
    Is_file_exist = False
    for line in stdout:
        print(line.strip('\n'))
        if filename in line.strip('\n'):
            Is_file_exist = True
    client.exec_command('cd '+dir_location+' && rm -rf *')
    client.close()
    return Is_file_exist
Sathish
  • 43
  • 1
  • 2
0

You may use Enabling Managed downloads by the Node. There are JAVA code examples in the documentation

Here is the C# code example. It has extra references and may not be used right away. But it should give a general understanding of how to perform it in C#

    public class SeleniumGridFileDownloadController
    {
        private readonly IDriverProvider _driverProvider;
        private readonly SeleniumGridApiClient _apiClient;

        public SeleniumGridFileDownloadController(IDriverProvider driverProvider, SeleniumGridApiClient apiClient)
        {
            _driverProvider = driverProvider;
            _apiClient = apiClient;
        }

        public string[] GetCurrentFiles() => _apiClient.GetDownloadFiles(GetSessionId()).Value.Names;

        public string DownloadFile(string downloadFileExtension, string downloadFolder, string[] previouslyDownloadedFiles, TimeSpan timeout)
        {
            var sessionId = GetSessionId();
            var newFileName = WaitForNewFileWithExtension(sessionId, downloadFileExtension, previouslyDownloadedFiles, timeout);
            var base64EncodedZippedContents = _apiClient.DownloadFile(sessionId, newFileName).Value.Contents;

            return UnzipFileContent(base64EncodedZippedContents, downloadFolder);
        }

        private string UnzipFileContent(string base64EncodedZippedContents, string downloadFolder)
        {
            var zippedBytes = Convert.FromBase64String(base64EncodedZippedContents);

            using var memoryStream = new MemoryStream(zippedBytes);
            using var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read);
            var archiveEntry = archive.Entries.Single();

            Directory.CreateDirectory(downloadFolder);
            var entryDestinationPath = Path.Combine(downloadFolder, archiveEntry.FullName);
            archiveEntry.ExtractToFile(entryDestinationPath, overwrite: true);

            return entryDestinationPath;
        }

        private string WaitForNewFileWithExtension(string sessionId, string expectedExtension, string[] previouslyDownloadedFiles, TimeSpan timeout)
        {
            return new ConditionWaiter
            {
                Timeout = timeout,
                Message = $"New {expectedExtension} file download"
            }.Until(() =>
            {
                var newFiles = _apiClient.GetDownloadFiles(sessionId).Value.Names;
                foreach (var newFile in newFiles)
                {
                    if (!previouslyDownloadedFiles.Contains(newFile))
                    {
                        var fileInfo = new FileInfo(newFile);
                        if (fileInfo.Extension == expectedExtension)
                        {
                            return newFile;
                        }
                    }
                }

                return null;
            });
        }

        private string GetSessionId() => GetDriver().SessionId.ToString();

        private RemoteWebDriver GetDriver()
        {
            var driver = _driverProvider.GetDriver();
            if (driver is not RemoteWebDriver remoteDriver)
            {
                throw new ArgumentException($"{nameof(RemoteWebDriver)} is expected but driver type is {driver.GetType().Name}");
            }

            return remoteDriver;
        }
    }

    public class SeleniumGridApiClient : WebServiceClient
    {
        public SeleniumGridApiClient(ILogger log, string baseUri) : base(log, baseUri)
        {
        }

        public SeleniumGridFileDownloadApiResponse DownloadFile(string sessionId, string fileName)
        {
            return NewRequest(Method.Post, $"session/{sessionId}/se/files")
                .AddApplicationJsonBody(new SeleniumGridFileDownloadApiRequest()
                {
                    Name = fileName
                })
                .AddHeader("X-REGISTRATION-SECRET", "")
                .Execute()
                .ShouldBeSuccess()
                .Deserialize<SeleniumGridFileDownloadApiResponse>();
        }

        public SeleniumGridDownloadedFilesListApiResponse GetDownloadFiles(string sessionId)
        {
            return NewRequest(Method.Get, $"session/{sessionId}/se/files")
                .AddHeader("X-REGISTRATION-SECRET", "")
                .Execute()
                .ShouldBeSuccess()
                .Deserialize<SeleniumGridDownloadedFilesListApiResponse>();
        }
    }
shatulsky
  • 306
  • 2
  • 10