Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility with Centos 6? #98

Closed
georaldc opened this issue Feb 2, 2017 · 20 comments
Closed

Compatibility with Centos 6? #98

georaldc opened this issue Feb 2, 2017 · 20 comments

Comments

@georaldc
Copy link

georaldc commented Feb 2, 2017

I've been trying to get dusk to work on my Docker setup which uses Centos 6.8 but seem to run into different issues. Unless I understand this wrong, I need Chrome installed to get chromedriver to work correct? Well I did just that (using https://chrome.richardlloyd.org.uk/ since newer versions Google Chrome do not support RHEL 6 anymore) and after trying to run the chromedriver-linux bin, I am met with library issues ('GLIBCXX_3.4.15' not found, 'CXXABI_1.3.5' not found, 'GLIBCXX_3.4.14' not found). I then read that I could get chromedriver to use the libraries from the chrome install I just performed (export LD_LIBRARY_PATH=/opt/google/chrome/lib). This does seem to make it work now

./vendor/laravel/dusk/bin/chromedriver-linux
Starting ChromeDriver 2.25.426924 (649f9b868f6783ec9de71c123212b908bf3b232e) on port 9515
Only local connections are allowed.

Unfortunately, trying to run ./artisan dusk -vvv gives me the following

PHPUnit 5.7.9 by Sebastian Bergmann and contributors.

Runtime:       PHP 5.6.30
Configuration: /var/www/html/mysite/phpunit.dusk.xml

and it stays there for a while before crashing with an error stating that the operation timed out. Is there anything else I'm missing to get this working?

@georaldc
Copy link
Author

georaldc commented Feb 2, 2017

Another thing I noticed is dusk doesn't seem to be starting up chromedriver properly when I run ./artisan dusk. I see it running the process via ps a but I just get a "couldn't connect to host" error. If I start chromedriver-linux manually, then I get the error I see earlier (Operation timed out after 30000 milliseconds with 0 bytes received).

EDIT:
Actually, it does seem to randomly run. Either way, I still have not been able to run any test at all because of the timeout problem.

EDIT2:
Well, could never figure out how to get chromedriver to work. I did get it to work with Selenium and Firefox but the example test ($browser->visit('/')->assertSee('text')) takes 15 seconds to complete. Any reason why?

@deleugpn
Copy link
Contributor

I'm trying on Centos 7 and facing the same problems as you. How did you run it on Firefox?

@georaldc
Copy link
Author

@deleugpn
Not sure about Centos 7 but to get firefox working, I installed the following via yum: java openjdk (for selenium), xvfb for headless testing (package is called xorg-x11-server-Xvfb.x86_64 on Centos 6) and the firefox browser itself. I then downloaded the selenium jar from http://selenium-release.storage.googleapis.com/index.html. All that's needed is to set the env variable DISPLAY to the same value you would use when running xvfb in the background, start up selenium, and modify your DuskTestCase file to comment out the googledriver line and to pass the right url + port to RemoteWebDriver. So something like the following:

# Set DISPLAY env variable and start xfvb and selenium
export DISPLAY=:0
Xvfb :0 -ac -screen 0 1280x720x24 &
java -jar /path/to/selenium-server-standalone.jar
// PHP. Edit DuskTestCase class driver() method
return RemoteWebDriver::create(
    'http://localhost:4444/wd/hub', DesiredCapabilities::firefox()
);

Yum gave me an old version of firefox, 45.7. If you use newer versions, I believe you would need to use geckodriver (https://github.com/mozilla/geckodriver). Just download the appropriate build and run selenium with it

java -Dwebdriver.gecko.driver=/path/to/geckodriver -jar /path/to/selenium-server-standalone.jar

Hope that helps, and hopefully it runs better for you. Selenium + firefox still takes 15+ seconds for every page load for me :(

@deleugpn
Copy link
Contributor

deleugpn commented Mar 6, 2017

I managed to run Dusk on Cent OS 7. I hope you can do the same on Cent OS 6. After installing Chromium Browser, you just need to create a separate user (NOT ROOT), turn on the Xvfb and run dusk as not root as well. If you want to run it specifically as root, you can try to run it with the arguments --no-sandbox.

login as: dusk
dusk@192.168.56.70's password:
Last login: Mon Mar  6 13:07:30 2017 from 192.168.56.1
[dusk@php7 ~]$ Xvfb -ac :0 -screen 0 1280x1024x16 &
[1] 2177
[dusk@php7 ~]$ cd /var/www/solucoesideais/laravel-dusk/
[dusk@php7 laravel-dusk]$ php artisan serve --host=127.0.0.1 --port=8000 --env=dusk.environment &
[2] 2186
[dusk@php7 laravel-dusk]$ Laravel development server started: <http://127.0.0.1:8000>

[dusk@php7 laravel-dusk]$ php artisan dusk
PHPUnit 5.7.15 by Sebastian Bergmann and contributors.

[Mon Mar  6 13:23:28 2017] 127.0.0.1:59146 [200]: /favicon.ico
.                                                                   1 / 1 (100%)

Time: 3.7 seconds, Memory: 10.00MB

OK (1 test, 1 assertion)
[dusk@php7 laravel-dusk]$

@georaldc
Copy link
Author

@deleugpn I tried updating my docker environment to Centos 7 and while that helped make running chromedriver much more easier, I still end up with similar "Operation timed out after 30001 milliseconds with 0 out of -1 bytes received" errors

@deleugpn
Copy link
Contributor

Check file permission, try to run the driver manually (confirm it's listening to port 9515) and check if you have Xvfb set.

@georaldc
Copy link
Author

georaldc commented Mar 30, 2017

So I've tried the following:

  1. Created a new user called "foobar"
  2. Switched to foobar. Set $DISPLAY to :0. Started Xvfb
  3. Ran ./artisan dusk as foobar

ps shows the following processes running

php ./artisan dusk
php vendor/bin/phpunit -c /var/www/html/BhamDashboard/phpunit.dusk.xml
/path/to/vendor/laravel/dusk/bin/chromedriver-linux
[chrome] <defunct>
[chrome] <defunct>

Not sure why chrome shows up twice but I can confirm that chromedriver is running under port 9515 since running a second instance manually would give me the "address already in use" message. Tests I have take 30 or more seconds each, timing out at the end

EDIT:
Forgot to add but I also have ./artisan serve running and my config APP_URL is set to http://localhost:8000

@deleugpn
Copy link
Contributor

deleugpn commented Mar 30, 2017

Set it up in a way that only one test will be executed (to speed things up). You can take advantage of --group=fail for this. Then, go to Laravel/Dusk/TestCase.php, line 207 and reduce retry from 5 to 2 times, also to speed things up. Lastly, go to your DuskTestCase.php and add more timeout:

        return RemoteWebDriver::create(
            'http://localhost:9515', DesiredCapabilities::chrome(), 150000, 150000
        );

This will probably be enough time for Chrome Driver to actually tell you what is wrong.

You can also try removing the retry completely for the purpose of this testing. The goal is to not rely on Facebook Webdriver's timeout settings. You want to let the application run until Chrome Driver gives you an error.

@georaldc
Copy link
Author

Interesting, I increased the timeout with your suggestion and I do see a clearer error: Chrome failed to start: crashed. I wonder if chromedriver was trying to start chrome from the wrong location? Need to look at some logs...

@deleugpn
Copy link
Contributor

I plan on writing a Medium post about this, but to sum it all up: Chrome Driver implements a HTTP protocol that Facebook Webdriver uses to manipulate the browser. As any HTTP Request, Facebook Webdriver relies on 30 seconds timeout. If you forget about Dusk completely, you can start chromedriver manually and then call it yourself through Postman (map your host machine with your guest machine through a access port). Then you can call something like GET 192.168.56.101:9515/sessions and chrome should reply with the sessions available or empty array. If you send a POST to /sessions, it will open a new tab for you and give you it's ID.

Basically this was the way that I used to debug everything. Do straight with POSTMAN + Chrome Driver with output logs and you'll be able to see what Chrome Driver is telling you. I remember going through the crash situation, I think it was indeed chrome installation. I think I ended up making a symbolic link for chrome on /usr/bin or something so Chrome Driver could see it.

After you learn how to manipulate Chrome Driver yourself, it's a piece of cake to understand how Dusk interacts with Facebook Webdriver to create an easy API for us to test the application.

@georaldc
Copy link
Author

georaldc commented Mar 30, 2017

So it seems that chromedriver, according to it's logfile, gets stuck trying to do a DevTools request to http://localhost:some-port-number/json/version over and over again, failing everytime until the timeout is reached. It's also calling the correct chrome binary, but chrome complains with the following error "Failed to move to new namespace: PID namespaces supported, Network namespace supported". If I try supplying the no-sandbox argument to Chrome, then it looks like Chrome starts to work with the following warnings:

Xlib: extension "RANDR" missing on display ":0"
NaCl helper process running without a sandbox!
Most likely you need to configure your SUID sandbox correctly

I read that these warnings can be ignored, but chromedriver still hangs repeatedly trying to do that DevTools request earlier.

@georaldc
Copy link
Author

I finally got it to work. For some reason, it seems like some fonts were needed so I had to run the following:

yum -y install liberation-mono-fonts liberation-narrow-fonts liberation-sans-fonts liberation-serif-fonts

Got the tip from here https://www.centos.org/forums/viewtopic.php?f=48&t=60908&start=10#p257122

I also need to use the --no-sandbox option. I could not get it to work without that option, even with a non-root user.

@deleugpn
Copy link
Contributor

deleugpn commented Mar 30, 2017

Did you install Chromium Browser instead of actual Google Chrome? Chromium Browser is supported by Google for RedHat while Google Chrome is a 3rd-party adaptation.

@georaldc
Copy link
Author

I installed google-chrome first (used the same script I previously needed to get chrome on Centos 6, https://chrome.richardlloyd.org.uk/). I then tried to install Chromium to see if I run into problems running it and got the same font errors as described in the centos.org link/post I put up. So I installed those fonts and now I'm able to get chromedriver to work with google-chrome.

So no, I'm not using Chromium Browser at the moment.

@deleugpn
Copy link
Contributor

I think I was only able to run Chromium without the sandbox flag, not Chrome.

@georaldc
Copy link
Author

georaldc commented Apr 17, 2017

@deleugpn I'm sorry if this isn't related to the issue, but I have a question for you. I believe you use Dusk with the internal PHP webserver correct? If so, would you happen to know of any workarounds when needing to make requests to yourself (like doing a CURL request to yourself from an ajax call)? The reason I ask is I know that mocking objects is a problem right now with Dusk and I figured I would just create a test API URL to points to myself (routes become available only during testing) to mock the responses for an external API my APP uses. Problem is I just realized that I would end up with a deadlock of sorts since the internal PHP webserver cannot handle more than 1 request at a time.

I've actually given up on trying to get Dusk to work on my dev environment. While I may have gotten Chrome to somewhat work, the actual testing part just executes too slow. This is probably related to Docker's slowness when working with shared files on a Windows host. So now, I'm just trying to run Dusk through my host machine instead and was hoping that I could just rely on PHP's internal server, instead of having to install a web server too on my host machine

@deleugpn
Copy link
Contributor

deleugpn commented Apr 17, 2017

you use Dusk with the internal PHP webserver correct

Yes. With php artisan serve --env=dusk.local &.

Ajax I know you won't have problems. I have a test that clicks on a button and waits for an ajax response and then asserts for database changes.

    /**
     * @test
     */
    public function it_should_rate_finished_ticket() {
        $user = factory(User::class, 'customer')->create();
        $ticket = factory(Ticket::class)->create(['status_id' => 4, 'user_id' => $user->id]);

        $this->browse(function (Browser $browser) use ($user, $ticket) {
            $rate = rand(1, 5);
            $browser->loginAs($user, 'customer')
                ->visit(new TicketsPage)
                ->click('#label-rating-1-item-' . $rate, $rate)
                ->assertRadioSelected('@rating-' . $rate, $rate)
                ->waitFor('@success-message');

            // Reload and Assert
            $ticket = $ticket->find($ticket->id);
            $this->assertTrue($ticket->rate == $rate);
        });
    }

The reason this works is because Dusk (through Facebook Web Driver) makes a HTTP request to Chrome Driver for a new Chrome Session. Once that is done we're inside the testable callback. When visiting a page, Chrome Driver will instruct the browser to load the page and once it's fully loaded, PHP Internal Server will rest (it's job is done). You cannot make an ajax call from the page until the page is fully loaded, hence you cannot deadlock it by making two calls. Chrome NEEDS to wait the page to be done so it can act and your action will be performed after the server is free to take your ajax request.

Now, when making a request from your controller, you might be right because Chrome is waiting for the PHP Server to reply with the page, but PHP Server would be waiting itself to reply an internal request, leading to deadlock.

@georaldc
Copy link
Author

georaldc commented Apr 17, 2017

So I guess there is no sane way to fake responses for server code that interfaces with an external API through the internal PHP web server, other than running things through an actual web server?

Would have been nice if mocking were possible, since then I would have just simply created an object that returned fixed responses instead of going through the wire.

@deleugpn
Copy link
Contributor

I have been bashing my head on mocking. My first dead end was trying to serialize a closure and then executing it from the PHP process that is invoked by Chrome. Now I'm trying with a static class and although I managed to serialize/unserialize it, calling Mail::fake() and Mail::shouldReceive('something') doesn't seem to be enough for the test to fail if I don't call Mail::something();.

@georaldc
Copy link
Author

That doesn't sound fun. I might just put environment checks inside my AppServiceProvider class and load mocked classes when under testing.

I'm closing this issue since I sort of found the answer to the cause of my main issue in the first place (getting chrome to run)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants