I would like to create a small Rails application that would allow users to give a few snippets of code to benchmark in multiple implementations and versions of Ruby. I am capable of creating the application, I am just afraid of users mucking around in the filesystem or doing other destructive actions. Is there any way to prevent this?
There is $SAFE:
The variable $SAFE determines Ruby's level of paranoia.
The various "safety levels" are noted at the link, there's also some examples (which still work) of using a thread, $SAFE, and load to wrap untrusted code. $SAFE on ruby might be worth a look as well.
Related
Suppose that I have a Java program that uses JRuby to allow the user to use Ruby scripting to control the behaviour of some funny character in a window.
Users can share their Ruby code with the community, so others can execute the snippets on their own copy of the program and see the funny character do stuff.
I have a security concern with this, though, as users may contribute malicious Ruby code to the community.
The obvious precaution is that users shouldn't run the snippets of untrusted users. However, due to the nature of the community, the point is to check out the creations of strangers.
So, it has occurred to me that maybe I can restrict the capabilities of JRuby.
There may be other things, but some of the restrictions off of my head would be:
Do not allow any sort of networking.
No access to the filesystem.
Do not permit system DOS calls.
Can't require/import ruby code/gems/etc.
Can't create new processes etc.
Is there a reasonable way to restrict JRuby functionality?
I have thought of, perhaps, redefining several constants that are required for that sort of operations. For instance,
File = nil
But I am unsure of what constants to nullify exactly, and whether this is effective at all.
since your requirements are concrete you would likely need to implement those restrictions yourself ... some pointers :
rubygems can be disable within JRuby - assuming it's fine for you to boot that way, otherwise chaing load/require is a good option
same for system and similar calls that create a new process
instead of doing File = nil early on you might end up needing to review File/IO methods one by one
undefine Java constant and java methods to disallow smart cheating with Java APIs
I am about to change my test automation language from Java to Ruby (I have new job where Ruby fits better into the tech stack).
I have a lot of experience with Java and Webdriver but can see that wrappers such as Watir and Capybara appear to be used more in Ruby than directly accessing the Webdriver API.
My concern about using a such a library is performance. I normally try integrate 3rd party grids such as Saucelabs into my test frameworks but have learnt that caching of selenium web element objects is important as continually finding elements can have a performance impact.
If I use libraries such as Capybara, do I lose the ability to control caching strategies? I have previously investigated Geb and found that the framework continually re-created webelements rather than caching, and it appeared inflexible in changing that behaviour.
Is my concern that these libraries help you to avoid writing boiler plate code but at the cost of performance valid?
TL;DR
Convention over configuration; use page-object for caching.
Here are my thoughts on this matter. And please consider this less of an answer, and more of a response for discussion. I want feedback on this answer, feel free to give it.
One of the primary patterns in Ruby (and it actually comes from Rails), is Convention over Configuration. The basic idea is that when there is a convention, either dictated by the language or the community, you roll with it whenever possible. In your case, I would recommend using the community frameworks if at all possible. This will make it easier for other developers to use your code and easier to seek help if you need it.
As far as the actual caching goes, with this I am less familiar. I do know the page-object gem stores elements instead of recreating them during every usage*. This would appear to conform with your requirements of caching elements. In any case, I highly recommend this gem as it enforces the page-object model of testing.
Note: I am not sure if the page-factory mixin supports this caching of objects, or if it recreates the class on every usage.
*You can see how the Element is stored in page-object by viewing the source code to the Element class.
def initialize(element, platform)
#element = element
I won't comment on performance in general as I haven't done extensive comparisons (and you shouldn't really believe anyone who can't point to benchmarks). However, here's a performance tip (with or without wrappers):
Internally, WebDriver uses HTTP to send commands to the browser (or an intermediate server). Since the protocol is quite chatty, you can often gain a lot by switching out the default Net::HTTP-based client with one that supports Keep-Alive (assuming the server supports it). That way the Ruby client will open one socket per browser and reuse it for the duration of the session, instead of opening one per command.
Here's code that uses the net-http-persistent gem:
require "selenium/webdriver"
require "selenium/webdriver/remote/http/persistent"
client = Selenium::WebDriver::Remote::Http::Persistent.new
driver = Selenium::WebDriver.for :remote, url: 'http://...', http_client: client
Unfortunately, I can't say anything specific about Capybara, but I can about watir-webdriver. By default, it always relocates element on the page, so you can't cache it. This behaviour can be turned off with
Watir.always_locate = false
though you can experience stale elements in this case (it, however, actually depends more on you just like with plain WebDriver). If you're planning you use watir-webdriver with page-object gem, its caching won't work as described in #screenmutt answer by default.
Also, there are two nice blog posts from Zejlko Fillipn about watir-webdriver performance when using SauceLabs and TestingBot.
Another issue of watir-webdriver is cross-browser performance. Because it uses XPath under the hood, you'll face significant performance problems when testing in IE.
I am writing a gem which adds dependencies to a gemfile from the command line. Given the gem name, it grabs the latest version from rubygems and adds it to the user's gemfile.
I practice test driven development using rspec. I'm wondering how do I mock the existence of a file and check it's contents?
Is there any pattern for doing this sort of thing? Tips, links or examples will help. I'm not set on a specific way of testing this. If mocking isn't the way to go, please let me know. Thanks!
If you want to mock a file object that only needs to be written and read from (no filesystem operations), try Ruby's builtin StringIO. Just require 'stringio', create a 'file' with any contents by using StringIO.new("Some contents"), and check its contents by using the string method on the StringIO object.
Unit Tests vs. Integration Tests
You didn't post any code, so I'm going to have to make some assumptions. In general, exercising behavior from Ruby's core or standard libraries is a waste of time. In addition, your tests should exercise methods that define class behavior, not necessarily every single method in a class.
When you cross the boundary to testing I/O, you're often doing integration tests. Sometimes integration tests are necessary, but they should make a very small subset when compared to unit tests.
With all that said, while integration tests that involve filesystem, database, or network I/O are often slower than unit tests, whether or not they are slow enough to warrant stubbing, mocking, or test-specific work-arounds will be specific to your code base.
Options for Testing
If you really need to do this, you have a lot of options. Some of these options include:
Using a RAM disk for your filesystem I/O.
Stubbing calls to IO, File, or FileUtils.
Avoiding the issue by using a file fixture.
Avoiding the issue by using a StringIO fixture.
Re-writing your class under test to accept String and/or StringIO in addition to File objects.
Using a gem like FakeFS to handle the stubbing/mocking for you.
This isn't meant to be an canonically exhaustive list. There are doubtless other options, but one or more of the above should handle any common use case.
If I have a ruby script Daemon that, as it's name implies, runs as a daemon, monitoring parts of the system and able to perform commands which require authentication, for example changing permissions, is there an easy way to have a second ruby script, say client, communicate to that script and send it commands / ask for information? I'm looking for a built in ruby way of doing this, I'd prefer to avoid building my own server protocol here.
Ruby provides many mechanisms for this including your standards such as: sockets, pipes, shared memory. But ruby also has a higher level library specifically for IPC which you can checkout Here, Drb. I haven't had a chance to play around with it too much but it looks really cool.
You may want to look into http://rubyeventmachine.com/
After being blown away by the greatness of irb and rails console, I am loving the dynamical parts of the language more and more. Now, I wonder if it would be possible for a Ruby application to update itself on-the-fly (if the write permission allows it). Can a Ruby application fetch an update and refresh itself? I have seen this functionality a lot in Apple applications and I know updates and fixes are something you must anticipate for when deploying an application.
Thank you for your feedback, comments and answers!
Sure. You can load a file that re-opens an existing class and alters behavior. There are a few ways to get the new code, too. Read it off disk, or have a socket that accepts connections and then eval the strings passed in. Or use HTTP: http://www.neurogami.com/articles/The_year_of_living_dangerously/
BTW, there's some risk involved with doing thngs this way. :)