MarkUs Blog

MarkUs Developers Blog About Their Project

Archive for the ‘Getting Started’ Category

How to use git with MarkUs

without comments

Here’s a simple rundown of some commands Tobi and I came up with in preparation for the sprint. You can use these to contribute to MarkUs. This post assumes you have already set up a github account and an ssh public key that you will be using later on.

Setting up MarkUs

  • Visit the upstream repo on github and select “Fork”. This will create a clone of the repository on your github account.
  • From your fork, copy the URL that allows you to access it using SSH.
  • Run the following command in terminal using the URL you just copied.
    $ git clone
  • Next, create a remote to the master repository of MarkUs upstream. This will be used to keep your local copy up to date.
    $ git remote add markus-upstream git://
  • Make sure the remote was added.
    $ git remote -v
    You should see “markus-upstream” and “origin”.
    Note the remote origin, it should point to the SSH URL you cloned with. If this URL contains “https”, then you have not cloned using SSH. Run the following command to change it to the URL used when cloning (see above).
    $ git remote set-url origin

Simple Development

From the MarkUs root directory in a terminal, run the following commands:

  • Create a branch
    $ git branch issue-1234
    $ git checkout issue-1234
  • Modify the files with the changes you want to implement. Let’s say I’ve modified Changelog and with the most amazing fix for issue 1234!
  • Take a look at the files you have modified
    $ git status
  • Then commit these changes
    $ git add Changelog
    $ git commit -m "FIX for issue 1234, implemented awesome function."
  • Before setting up a review request, make sure your issue and master branches are up to date (see below), making sure the changesets you just pulled in do not affect your code. Once they are, setup a review request.
    $ git push origin issue-1234
    Go to your github fork and change to your issue branch. You should see the button “Pull Request” (right by the button to fork). In the write fill, fill it in with the issue number, quick summary of the issue, desciption of the fix and what testing was performed.

Keeping your local clone up to date

  • First, make sure you have already set up your upstream remote. Note, mine is called "markus-upstream". Substitute your remote name whenever you see this. Run the following commands from terminal.
  • To update your local master branch $ git checkout master $ git pull markus-upstream master
  • To integrate these changes into your current issue branch $ git checkout issue-1234 $ git merge/rebase master

Some useful commands

  • Setup your git configuration settings. $ git config --global "First-name Last-name" $ git config --global ""
  • View what changes you have made on branch "issue-1234"
    $ git diff --full-index master issue-1234
  • Temporarily put  your changes aside to have a cleanly tracked branch $ git stash Bring these changes back (even onto another branch, as long as it is within the same repository) $ git stash pop
  • Remove all changes made to a specific file. Let's say I no longer want the changes I've made to app/models/membership.rb $ git checkout app/models/membership.rb
  • Revert all changes made to the current branch (WARNING: All changes will be lost). $ git reset --hard HEAD
  • Once your branch, issue1234, has been integrated into master, you might want to delete it. $ git branch -d issue1234 $ git push origin :issue1234
  • You might want to see who added/modified a line last, and what other changes they brought in with that changeset. $ git blame config/routes.rb This might be easier to do directly on github though! Here's an example.

Written by Danesh

January 28th, 2012 at 7:14 pm

Posted in Uncategorized

The 2011 Winter Team

without comments


My name is Yansong, I’m currently an international student at SFU. I come from China and arrived in Vancouver on Sep. 5th 2010. Vancouver is such a beautiful place and I really enjoy living and studying here!

I’m major in Computing Science and now in my 3rd year, actually I spent my first two years of college study in ZU, China. During my study at ZU, I once worked on a web-based project when I was taking the course Software Engineering. That project is developed in PHP, the database we use is MySQL and there are also some script languages we use like CSS and JavaScript in that project. I’m very interested in learning new programming languages and looking forward for working with Ruby on Rails!

I chose CS major because I like coding and really enjoy the feeling of working together with a group of brilliant guys to achieve the same goal and racing with the time. When I was doing the course Software Engineering, there always be a big DEADLINE ahead coming closer and closer, while with the hard work of my teammates and I we finally went through and got the highest scores in that course! This experience brought me both hardship and happiness.

Now with the help of our nice and warm supervisors I believe we all will learn much in this project and let’s make our MarkUs better and better!

Following is my photo taken in Stanley Park

Misa Sakamoto
U of T

My name is Misa and I’m a 4th year in CS: Software Engineering at UofT. This will be my second term working on MarkUs. This summer term, I worked on a web-based repository browser project for Basie, using Pinax/Django. I also just finished a 16month internship at IBM. Aside from programming, I’m also interested in psychology, teaching, and dogs 🙂

Ibrahim Shahin
U of M

My name is Ibrahim and I’m a fourth year Computer Science student at the University of Manitoba. I’ve worked at Electronic Arts, developing various tools and working on metagame design, and at Frantic Films/Prime Focus, developing pipeline tools for artists. My main areas of interest in computer science are artificial intelligence and human-computer interaction.

I haven’t done much web development or Ruby on Rails which is why I wanted to work on Markus. In my spare time, I enjoy reading, watching movies, and playing video games.

Karel Kahula
University of Manitoba

My name is Karel. I am a fourth year Computer Science student at the U of Manitoba. I became interested in Computer Science because I like the feeling of solving problems, improving existing systems and the team work involved in designing solutions.

My previous experiences include web application development for Wawanesa Insurance, database application support for the Province of Manitoba and pipeline tool development at Prime Focus.

Outside of school and programming, I enjoy traveling, watching movies and playing video games.

Concentration gives me googley-eyes.

Danesh Dadachanji
U of T

Hello everyone, my name is Danesh and I am a 3rd year undergrad at the University of Toronto. I started out as a Math major with a first year CS course on the side but I almost immediately changed to CS because I found it much more enjoyable. Since then I’ve become very active in the community and as of this year have joined the student union.

As a project for my software engineering course, I worked on an announcement system website for a high school in the GTA. It was done using the PHP framework, CodeIgniter and a MySQL database. I’ve also programmed in Java, Python and C.

I enjoy playing video games (when I’m not buried under school work) and love to snow board. I also have a tendency of scripting in bash and automating something or the other while I’m procrastinating.

Tobi Ogunbiyi

U of T

Hello, I am a third year student studying Computer Science, specializing in Software Engineering. I chose to study Computer Science because I enjoy solving problems through programming. My experience with MarkUs so far has been in submitting programming assignments. As soon as I got to know that MarkUs is one of the projects offered by UCOSP, I was interested in developing MarkUs.

My skill set has been greatly influence by programming in Java, Python, C, and Bash Scripting. A lot of the experience I have was obtained has been in Java and Python. I have also had to slam together scripts in Bash. I look forward to learning a lot of Ruby and Rails programming while I contribute to the project.

I love the outdoors so during my leisure time, I like to play outdoor soccer, outdoor basketball, the drums, and video games (I am a huge fan of Steam! :D). I am really excited about working with you on MarkUs and I look forward to meeting you.

Written by Yansong

January 15th, 2011 at 1:38 am

Posted in Uncategorized

Getting Started with Machinist in Markus

with 3 comments

When running, we almost always have to set up some objects to test. We used to set up these objects by loading them from fixtures. There is a problem with fixtures. It’s hard to know the attributes of the objects or the relationships between different objects unless we delve into fixture files. This is not good, because when doing tests and making assertions, we want to know well about the objects we tested against, but looking into fixtures is a time-consuming job. Now don’t you want a mechanism that allows you to explicitly create objects and build up the relationships among them, but without having to specify their attributes that you don’t care about? This is what Machinist does! With Machinist, you can create and save an assignment object by writing one short line in your code: “assignment = Assignment.make”. Isn’t that great?

In his post, Fixtures are not as clear as Machinist, Robert has a deep insight on how Machinist is better than fixtures.

Yes, Machinist is great, and I promise you’ll find it even greater if you spend a little time reading through Machinist’s documentation. Make sure you understand what a blueprint is and how we can pass attributes to “make” method and override its default behaviour.

The documentation pretty much tells all you need to know about Machinist. I’m not going through every details here, but there are some stuffs you may want to know about how we can use Machinist with Markus.

1. Setting up the playground for Machinist

Before using Machinist, please make sure you’ve installed two gems: Machinist and Faker. If they are not on your machine, you can run the following command in a terminal:

 gem install faker machinist --source 

Now that the gems are installed, you want to build some confidence in Machinist by making some easy objects. The easiest way to play around with Machinist is to open a script/console with test environment. You can do this by opening a terminal, change the directory to the root directory of your Markus’ project, and then run the following command:

 script/console test 

Make sure you append the “test” option, which loads test environment for you. Otherwise you’ll be at the risk of screwing up data you use for dev.

If you see something like

Loading test environment (Rails 2.3.5)

you’re already in the script console. In script console, you can execute any Ruby code as you would normally write in .rb source files. If you’ve not used script console before, try to “new” an empty group object to get yourself familiar with it.

>> group =
=> #<Group id: nil, group_name: nil, repo_name: nil>

“group =” creates a new empty group, whose information is displayed in the console.

Now you probably cannot wait to use Machinist. OK, let’s start by making a group which is the easiest model I can find in Markus. Try to execute the following line in the script console.

>> group = Group.make

But you’re likely to get this:

NoMethodError: undefined method `make' for Group(id: integer, group_name: string, repo_name: string):Class
 from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1959:in `method_missing_without_paginate'
 from /var/lib/gems/1.8/gems/will_paginate-2.3.12/lib/will_paginate/finder.rb:170:in `method_missing'
 from (irb):5

Why? If you’ve read the Machinist’s documentation, you should’ve already known the reason. You cannot use the “make” method of a model unless you’ve defined the its blueprint. OK, then let’s write the blueprint. Wait, in fact, you don’t need to, because blueprints for most models in Markus are already defined in /test/blueprints/blueprints.rb, which is “required” by /test/blueprints/helper.rb. To make a reference of these blueprints, you only need to run the following line in script console:

>> require "test/blueprints/helper.rb" 

Now try to “make” your group object again, and see what happens. If you still get an error, please don’t panic, and skip ahead to read the next section, where you’ll find the answer. But most likely you will be lucky to see a sign of success in your script console like the one I get here:

=> #<Group id: 930503258, group_name: "group1", repo_name: "group_930503258"> 

See, with only one simple call of “make”, you have already created a group object with all the attributes set properly. That’s why we all like Machinist!

Congratulations. You’ve already set up the playground for Machinist. At this point, you are good to go. Just try out any of your ideas with Machinist.

2. Common Issues

Sometimes, when you make a make an object, you get an error message like this: “ActiveRecord::RecordInvalid: Validation failed: Group name has already been taken”. This message means in the database there is already a group object with the same group name as the one you are just making. The test database can persists objects as a result of your last test, so you should clear the database before playing around with Machinist. To delete all the objects of a model in database, you can call “ModelName.delete_all”, where ModelName is the name of the Model whose objects you want to delete. But it’s is more desirable to clear all the table at the same time. Here is the code to do that:

(ActiveRecord::Base.send :subclasses).each {|c| c.delete_all}

I recommended you to use script console. But it has an issue. Everytime you modify and save blueprints.rb, you need to restart the script console for it to detect the change. This makes it inconvenient for you to do test your blueprints. As an alternative to script console, you can create a .rb file at your project’s root directory, and put the following lines at the beginning:

ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/config/environment")
require File.join(File.dirname(__FILE__), "test/blueprints/helper")

This should also set you up a test environment where you can write code to play around with Machinist. The benefit of this approach is that it makes it easy to test blueprints.

3. Making Objects with Associations

There are three common types of associations: “belongs_to”, “has_many” and “has_one”.

belongs_to“: if A “belongs_to” B, a.b should be not nil and unique. It’s identical to a foreign key relationship from A to B. B should be made prior A. A’s blueprint should take care of making B. For example in Markus, Student belongs Section. The blueprints for Section and Student are:

Section.blueprint do

name {Sham.section_name}

Student.blueprint do
type {'Student'}
user_name {Sham.student_user_name}

The blueprint of Student implicitly calls Section.make. Therefore, when you call Student.make, a section will be made before student. If you already have a section object my_section and want to make a student that belongs to that section, you can call Student.make({:section => my_section}), which overrides the default behaviour specified by Student blueprint and doesn’t make a new section. When you make an object, you may end up making lots of  other objects because the “belongs_to” association “recursively” makes the dependencies.

has_many“:  if A “has_many” B, then B “belongs_to” A. Machinist encourages you to first create the object on the right hand side of “belongs_to” association (seeking for some better wording here). Using the example of Student and Section. Section belongs to Section, and thus Section has many Students. When you want to make a section with many students, you need to make a section first. We are still using the blueprints from the previous example:

section = Section.make


When section.students.make is called, Machinist is smart enough to call  Student.make({:section => section}). So you don’t need to worry about accidentally creating a new section. After the two lines, you have section.students.first.section == section.

has_one“: “has_one” is a special case of “has_many”. if A “has_one” B, then B “belongs_to” A. Same as “has_many”, A should be made prior to B. Suppose we have two models: Coach and Team, where Team “has_one” Coach and Coach “belongs_to” Team. You may attempt to make an object of Team in a similar way to “has_many” association:

team = Team.make

coach =

But it doesn’t work. In the “has_many” example, section.students is a collection which is an object not nil, but here is nil. There is no way for Machinist to know which blueprint to use for making a nil object. So what you have to do is:

team = Team.make

coach = Coach.make({:team => team})

Then you can use the team object.

Submission.blueprint do
submission_version {1}
submission_version_used {true}
revision_number {1}
revision_timestamp {1.days.ago}

Written by bryanshen

March 10th, 2010 at 3:51 am

Posted in Uncategorized

Fixtures are not as clear as Machinist

with 4 comments

I’m in the process of converting some unit tests (for Students and Assignments) away form fixtures and onto Machinist. I decreed at the weekly meeting that I was going to be finished this by the end of the weekend, and from the time this is posted, I’ve failed. I started later than I should have, and clearly didn’t account for enough debugging time.

“But wait!” I hear you clamour. “You’re just moving tests from one framework to another, right? Surely such things could be done by robots and other automatons?” Indeed! In an ideal world this would be true. But in this world, we will encounter exceptional circumstances and end up using our brain. Here is my tale…

This is a telling observation from the fixture tests:

Half the time, I’m not sure what’s being tested.

Here is a typical example:

<br />
def test_create_group_for_working_alone_student_existing_group<br />
    assignment = assignments(:assignment_1)<br />
    student = users(:student1)<br />
    # The test code...<br />
end<br />

The rote way of converting this to machinist is like so:

<br />
def test_create_group_for_working_alone_student_existing_group<br />
    assignment = Assignment.make<br />
    student = Student.make</p>
<p>    # The test code...<br />
end<br />

Pretty simple right? Awesome!

However, all is not well in testerland. Watch when I run it:

<br />
Testing started at 10:43 PM ...</p>
<p>NoMethodError: undefined method `allow_web_submits' for nil:NilClass<br />
app/models/group.rb:49:in `repository_external_commits_only?'<br />
    app/models/grouping.rb:333:in `update_repository_permissions'<br />
    app/models/student.rb:118:in `create_group_for_working_alone_student'<br />
    test/unit/student_test.rb:142:in `test_create_group_for_working_alone_student_existing_group'<br />
    /Applications/RubyMine `run_suite'<br />
    /Applications/RubyMine `start_mediator'<br />
    /Applications/RubyMine `start'<br />
1 tests, 0 assertions, 0 failures, 1 errors<br />
Test suite finished: 0.860263 seconds</p>
<p>Process finished with exit code 1<br />

Now there’s a tasty bowl of error soup!
What the heck happened? We were using a student and an assignment, shouldn’t it just work?

I look into the fixtures for both :student1 and :assignment_1 to see what went wrong.

<br />
# in users.yml<br />
student1:<br />
  user_name:      student1<br />
  last_name:      Mason<br />
  first_name:     Hollis<br />
  grace_credits:     5<br />
  type:           Student<br />
  section_id:     <%= Fixtures.identify(:section1) %><br />
  created_at:     <%= %><br />
  updated_at:     <%= %><br />
  hidden: false</p>
<p># in assignments.yml<br />
assignment_1:<br />
   short_identifier: Captain Nemo<br />
   description: "Code!!"<br />
   message:<br />
   due_date: <%= 30.days.from_now.to_s(:db)%><br />
   group_min: 2<br />
   group_max: 4<br />
   student_form_groups: true<br />
   instructor_form_groups: false<br />
   group_name_autogenerated: true<br />
   group_name_displayed: true<br />
   created_at: <%=><br />
   updated_at: <%=><br />
   repository_folder: CaptainNemo<br />
   marking_scheme_type: "rubric"<br />
   allow_web_submits: false<br />

Both look pretty routine, so now I’m at a loss of what to do. The only thing I’ve got to go on is the error message. But why am I getting it in the first place? The only thing that looks related to the error is the allow_web_submits property, which is being set to false. I update the make line to the following, to ensure consistent results.

<br />
    assignment = Assignment.make(:allow_web_submits => false)<br />

That’s not the big error though, why in the world is this being checked on a nil object? Where’s that happening? It’s raising in groups.rb, but where the heck were those set up?

Oh. They are… They are just in the yml files for the groups, groupings, and memberships fixtures.

A little tinkering around and my knowledge of how Assignments, Students, Groups, Memberships, and Groupings are organized gives me the final working test, that emulates the relevant conditions in the fixtures.

<br />
  def test_create_group_for_working_alone_student_existing_group<br />
    group = Group.make<br />
    assignment = Assignment.make(:allow_web_submits => false)<br />
    grouping = Grouping.make(:group => group, :assignment => assignment)<br />
    membership = StudentMembership.make(:membership_status => 'inviter', :grouping => grouping)<br />
    student = membership.user<br />
    # Same old Test code....<br />
  end<br />

Not at all the same, is it? The fixtures were hiding all the delicious dependancy information from me. In the end, I had to improvise a bit. From all the information, and time spent in the yml files determining the purpose of this particular test wasn’t easy. You needed to know exactly how the fixtures were set up in relation to each other, which involved look into half a dozen files. This is not ideal.

The purpose of a good test should be clear to anyone with some information about the system tested. In the case above, the test was that a student with a grouping already doesn’t cause an error when put into a separate group by themselves.

Beyond the assertion and the function name, I didn’t know what’s being tested. I didn’t know why those particular fixtures, :student1 and :assignment_1, were picked from the other students and assignment fixtures. The only way to find out is to directly delve into the .yml files that define them. That didn’t even guarantee that I understood the purpose of the test.

Before I submit this, I’ll likely need to check to see if each method is being adequately tested. Even if the tests were comprehensive under fixtures, it’s not clear that the same conditions are being met now. Thats not a vote to stay with fixtures though. Fixtures are bad because they move the preconditions away from the test, making it unclear under what circumstances the desired behaviour is to occur. Such a framework becomes brittle when writing new tests. Would you want add new fixtures, or see if some combination of the previous ones emulate the conditions of your test? With Machinist, you can construct what you need. When some other dev comes along, they might not know exactly why it was set up that way, but they will know what the setup is, and how you want the parts to be tested to interact.

Written by Robert B

February 22nd, 2010 at 1:48 am

Posted in Uncategorized

Ruby on Rails (RoR) from a Java programmer’s perspective

with one comment

Java is a static-typed language, and every variable, method and class is explicitly defined. It’s very easy to find their definition with a little help from IDE.

When I started to program Markus in RoR, I still think in the Java way, and find something very confusing. Here is some code I saw in Assignment class:

# Are we past the due date for this assignment?
class Assignment < ActiveRecord::Base
 # some code here

 def past_due_date?
    return !due_date.nil? &amp;amp;amp;&amp;amp;amp; > due_date

 # some code here

I was curious of what “due_date” is, so I naturally did an “Open Declaration” in Eclipse IDE, which gave me no feedback at all. This happens because RoR types are dynamic, and type information is not available until run-time.

Then I searched for “due_date” across the whole project, and found some references of “due_date” but no definition of it at all.

What is it? Is it an instance variable? No, the name of an instance variable always begins with “@”. Is it a local variable? No, local variable should be initialised before being used. It should be a method. Yes, it’s a method, but where is it defined?

After turning to Mike and Severin, I eventually understood that “due_date” was not defined explicitly. It was created by ActiveRecord. ActiveRecord noticed that “due_date” was a column in the database table associated with Assignment, and therefore creates the “due_date” method (getter and setter) automatically. [The database schema]

This seems incredible to a Java programmer. In Java, a method should be explicitly defined before you use it. But in RoR, you don’t necessarily have to define a method to use it – methods can be created at run-time. Finally I realised this is why we call RoR “dynamic”. And for the first time I see the benefit of being dynamic: the chunky data-object mapping code is eliminated by the magic of dynamic!

Next time, when you cannot find the definition of something, don’t be panic, but think “dynamic”.

Written by bryanshen

February 9th, 2010 at 12:40 am

Posted in Uncategorized

Learnings from my first changelist

without comments

Weird Behaviour of Mocha

In the markus code, there are a lot of places where we use markus_config_&lt;something&gt; instead of MarkusConfigurator.markus_config_&lt;something&gt;. We should start using the latter. He’s why:


def self.check_config()
puts "Checking #{markus_config_logging_logfile}"
puts "Checking #{markus_config_logging_errorlogfile}"
puts "Checking #{markus_config_repository_storage}"
puts "Checking #{markus_config_validate_file}"
puts "Checking #{MarkusConfigurator.markus_config_logging_logfile}"
puts "Checking #{MarkusConfigurator.markus_config_logging_errorlogfile}"
puts "Checking #{MarkusConfigurator.markus_config_repository_storage}"
puts "Checking #{MarkusConfigurator.markus_config_validate_file}"
check_in_writable_dir(markus_config_logging_logfile, "MARKUS_LOGGING_LOGFILE")
check_in_writable_dir(markus_config_logging_errorlogfile, "MARKUS_LOGGING_ERRORLOGFILE")
check_writable(markus_config_repository_storage, "REPOSITORY_STORAGE")
check_readable(markus_config_repository_storage, "REPOSITORY_STORAGE")
if ! RUBY_PLATFORM =~ /(:?mswin|mingw)/ # should match for Windows only
check_executable(markus_config_validate_file, "VALIDATE_FILE")

Output from running rake test:units When loading everything up:

Checking log/info_development.log
Checking log/error_development.log
Checking /home/jmate/everything/workspaces/repos
Checking /home/jmate/everything/workspaces/markus/config/
Checking log/info_development.log
Checking log/error_development.log
Checking /home/jmate/everything/workspaces/repos
Checking /home/jmate/everything/workspaces/markus/config/

At this point, &lt;blah&gt; == MarkusConfigurator.&lt;blah&gt;

When running the test cases:

Checking log/info_test.log
Checking log/error_test.log
Checking /home/jmate/everything/workspaces/repos
Checking /home/jmate/everything/workspaces/markus/config/
Checking /tmp/ensure_config_helper_test_777699315/log/log_info_file.log
Checking /tmp/ensure_config_helper_test_777699315/log/log_error_file.log
Checking /tmp/ensure_config_helper_test_777699315/source_repo_dir
Checking /tmp/ensure_config_helper_test_777699315/
Checking log/info_test.log
Checking log/error_test.log
Checking /home/jmate/everything/workspaces/repos
Checking /home/jmate/everything/workspaces/markus/config/
Checking /tmp/ensure_config_helper_test_473533902/log/log_info_file.log
Checking /tmp/ensure_config_helper_test_473533902/log/log_error_file.log
Checking /tmp/ensure_config_helper_test_473533902/source_repo_dir
Checking /tmp/ensure_config_helper_test_473533902/

Now you can see that &lt;blah&gt; != MarkusConfigurator.&lt;blah&gt; . So the namespace for the method you are trying to call cannot be ambiguous. In the source code above you must use MarkusConfigurator.&lt;blah&gt;.

Mocking Modules with Mocha

I could not find any examples on mocking modules with mocha. It’s probably because it’s so easy! It’s just like mocking an instance of a class.

the_module.rb :

module TheModule
def the_module_function
return "the real value"

test.rb :

require "test/unit"
require "mocha"
require "the_module"
include TheModule

class TheModuleTest &amp;amp;amp;amp;amp;lt; Test::Unit::TestCase
# replace 'the real value' with 'the mocked value'"
def test_it
assert TheModule.the_module_function == "the real value"

TheModule.stubs(:the_module_function).returns("the mocked value")

assert TheModule.the_module_function == "the mocked value"

Running the tests:

jmate@CalculatorJozef:~/everything/workspaces$ ruby test.rb
Loaded suite test
Finished in 0.00096 seconds.

1 tests, 2 assertions, 0 failures, 0 errors

Nested Contexts

I learned a new trick with shoulda. Credit goes to:

You can nest contexts inorder to resuse them.

Here is a quick example I prepared:

context "we have a temp dir" do
setup do
@temp_dir = "/tmp/temp_#{rand(1073741824)}"&amp;amp;amp;amp;amp;lt;/pre&amp;amp;amp;amp;amp;gt;
@log_dir = "#{@temp_dir}/log"
@file = "#{@log_dir}/file"
FileUtils.mkdir( @temp_dir )
teardown do
FileUtils.rm_r( @temp_dir )
should "be able to test with the temp dir" do

context "we have a log dir" do
setup do
FileUtils.mkdir( @log_dir )
should "be able to test with the temp and log dir" do

context "we have a file inside the log dir inside the temp dir" do
setup do
FileUtils.touch( [@file] )
should "be able to test with temp, log and file" do

Permissions, Directories and Ruby

I recently learned that if you remove the execute bit on a directory and try to rm -r the parent directory then you will be unable to remove the executable directory. However, this works in a terminal.

Example in ruby:

#!/usr/bin/env ruby
require 'fileutils'
include FileUtils

@parent_dir = "/tmp/parent_#{rand(1073741824)}"
@test_dir = "#{@parent_dir}/test"
@file = "#{@test_dir}/file"

FileUtils.mkdir( @parent_dir )
FileUtils.mkdir( @test_dir )
FileUtils.touch([ @file ])
FileUtils.chmod( 0600, [ @test_dir ])
FileUtils.rm_r( @parent_dir )

Output from script:

jmate@CalculatorJozef:~/everything$ ./test.rb
/usr/lib/ruby/1.8/fileutils.rb:1297:in `unlink': Permission denied - /tmp/parent_674314876/test/file (Errno::EACCES)
from /usr/lib/ruby/1.8/fileutils.rb:1297:in `remove_file'
from /usr/lib/ruby/1.8/fileutils.rb:1302:in `platform_support'
from /usr/lib/ruby/1.8/fileutils.rb:1296:in `remove_file'
from /usr/lib/ruby/1.8/fileutils.rb:1285:in `remove'
from /usr/lib/ruby/1.8/fileutils.rb:756:in `remove_entry'
from /usr/lib/ruby/1.8/fileutils.rb:1335:in `postorder_traverse'
from /usr/lib/ruby/1.8/fileutils.rb:1335:in `postorder_traverse'
from /usr/lib/ruby/1.8/fileutils.rb:1339:in `postorder_traverse'
from /usr/lib/ruby/1.8/fileutils.rb:1334:in `postorder_traverse'
from /usr/lib/ruby/1.8/fileutils.rb:1333:in `each'
from /usr/lib/ruby/1.8/fileutils.rb:1333:in `postorder_traverse'
from /usr/lib/ruby/1.8/fileutils.rb:1334:in `postorder_traverse'
from /usr/lib/ruby/1.8/fileutils.rb:1333:in `each'
from /usr/lib/ruby/1.8/fileutils.rb:1333:in `postorder_traverse'
from /usr/lib/ruby/1.8/fileutils.rb:754:in `remove_entry'
from /usr/lib/ruby/1.8/fileutils.rb:612:in `rm_r'
from /usr/lib/ruby/1.8/fileutils.rb:608:in `each'
from /usr/lib/ruby/1.8/fileutils.rb:608:in `rm_r'
from ./test.rb:14

Example in terminal:

jmate@CalculatorJozef:/tmp$ mkdir parent
jmate@CalculatorJozef:/tmp$ mkdir parent/test
jmate@CalculatorJozef:/tmp$ touch parent/test/file
jmate@CalculatorJozef:/tmp$ rm -r parent

As you can see from the output above. I had no trouble doing this in the terminal.

It might have something to do with not being able to cd into a directory that does not have the execute bit set.

I hope the knowledge I pass on helps you guys:

Ruby Permissions and Directories

Nested Contexts

Mocking Modules with Mocha

Weird Behaviour With Mocha


Written by jmate

January 30th, 2010 at 11:14 pm

Posted in Uncategorized

Sharing some newbie’s experience, =P

with 2 comments

In last week, I fixed the bug #570. Although this bug is not a difficult one, I do learn a lot in the process fixing it. I would like to share some experience of it. My route may not be as efficient as yours, please feel free to advice a better way. I need you guys’ suggestion to improve my skills,=P.

Firstly, I used the following way to find the place to start. For example, in the #570, the problem is the string not being stripped. Without much knowledge about the project structure, I just ran the project, opened the firefox with firebug running, and then find the string name “user_name” in the table on the page of adding user. After I got the string name I made a search in the project of “user_name” which returned quite a lot of results. Then I started to browse those results to find target methods like “create”, ”add”, “update” etc. I did find these methods in “/controllers/students_controller.rb” which use the parameter params[:user] to create the new student records.

At first glance this seemed to be the place to modify the string, and I modified the string here, which did work when I did some manual tests. However, I noticed that there are at least 3 controllers of “student”, ”ta” and “admin” that use very similar methods. If I applied the rough ideas I will need to modify at least 3 places that will potentially bring difficulty of maintenance in future. Then I started to think about finding the original place of this user object. Some places that I suppose things like the string validation would happen. When I noticed that there is a User class that are inherited by “student”, ”ta” and “admin”, I knew this is the right place to do the job.

However, I didn’t know how to do this due to my lack of knowledge of Rails. Well, here I learned how to save your time by asking your team members who know the projects well and are willing to help,=). Just asked a quick question to Mike and he pointed out that there are some callbacks in ActiveRecord that we can use to validate the variables at different states. Then I started to search the web and figured out how to use it. A new method was added to User class to trip all the input strings. At this point I have already solved half of the problem. It was exciting to me!

The next step will be adding test cases for this new method. Again, communication is really important and I learned how to write the test cases from Mike. Here are some rough steps I did for my tests:

  1. Make sure you have no error and no failure before your modification to the project.
  2. Find the unit test under test/unit. There is usually a name matching from the test case to the tested class. For example I found the “user_test.rb” test “user.rb”.
  3. I have no idea how to write the test cases at first. I talked to Mike and also took a look at existing test cases. As suggested, we shall use shoulda to test because it is better for reading. For me, I didn’t really search tutorials of shoulda on the web. I just found some existing codes in our project and figured out the basic structure is like:

context “some one” do

  1. setup do
  2. end
  3. should “do something” do
  4. assert something
  5. end
  6. end

Basically “setup do” is the place to put the setup of your test values. And “should” is the place to add the function you perform like user. save, and tests you add like assert, assert_nil, assert_equal. You can add multiple shoulds within a context.

When your run the test by typing ruby -Itest test/unit/sometest.rb, it will give the result like “some one do something <false> is not true “when your test case fails.

4. I suggest after you pass the single test that you modified, run a full tests (rake test:units) to make sure you pass all the rest tests as well.

Check our last irc meeting log, you will find some useful tips about testing.

Above are some thoughts I come up with my experience of solving #570. I hope it suggest some useful points. If you get confused at some points, please let me know. I would try to explain. And I am also willing to hear  from you guys,=).

Written by Brian Xu

January 24th, 2010 at 8:34 pm

Posted in Uncategorized