CSCI 265: Fall 2018 Midterm Sample Solutions

NOTE: THE MIDTERM MARK WAS ACTUALLY RECORDED OUT OF 32, NOT 40

Question Mark
1. Git, branch, merge
[8 marks]
 
2. Bash and defensive programming
[8 marks]
 
3. Bash scripting
[8 marks]
 
4. Specifications
[8 marks]
 
5. Life cycle models
[8 marks]
 
Exam Total

[40 marks]

 

Question 1: Git, branch, merge [8]

(i) Provide the exact sequence of git and bash commands necessary to enact the steps described below.

(ii) Identify the points where merge conflicts would need to be addressed, and which specific file(s) would be the source of conflict(s).

  1. Create a new directory named proj, cd into that directory, and initialize it as an empty git repository.
  2. Copy all the .cpp files, .h files, and makefile from a directory named /src/core into the proj directory, add them all to git, and commit with the message "core content".
    The files in /src/core are: readme, layout.txt, makefile
    numTypes.h, numTypes.cpp, data.h, data.cpp, hash.h, hash.cpp
  3. Create a new branch named "altData", then switch to the new branch
  4. Use an editor (your choice) on files hash.cpp, newdata.cpp, makefile
    (you don't need to show any actual changes to the files, just the command to start the editor ... we'll assume changes are actually made)
  5. Delete the file data.cpp
  6. Perform appropriate git adds for the altered/added/removed files, and commit with the message "first altData changes"
  7. Switch back to the master branch
  8. Use an editor on the data.h file, then add it and commit with the message "updated master data"
  9. Create a new branch named "altTypes" then switch to the new branch
  10. Use an editor on the data.h and numTypes.h files, then add them and commit with the message "first altTypes changes"
  11. Switch back to the master branch
  12. Merge the content of the altTypes branch into the master branch
  13. Use an editor on the makefile, then add it and commit with the message "updated master make"
  14. Merge the content of the altData branch into the master branch

Sample Solution

(1) mkdir proj
    cd proj
    git init
(2) cp /src/core/*.h .
    cp /src/core/*.cpp .
    cp /src/core/makefile .
    git add .
    git commit -m "core content"
(3) git branch altData
    git checkout altData
(4) vim hash.cpp newdata.cpp makefile
(5) git rm data.cpp
(6) git add .
    git commit -m "first altData changes"
(7) git checkout master
(8) vim data.h
    git add .
    git commit -m "updated master data"
(9) git branch altTypes
    git checkout altTypes
(10) vim data.h numTypes.h
     git add .
     git commit -m "first altTypes changes"
(11) git checkout master
(12) git merge altTypes  [note: there is no conflict here since altTypes
                          was created after master's changes to data.h,
                          so it has only changed in one branch]
(13) vim makefile
     git add .
     git commit -m "updated master make"
(14) git merge altData [note: there is a merge conflict here in makefile,
                        since it has been altered in both branches]

Question 2: Bash and defensive programming [8]

In a recent lecture we discussed defensive programming and the desire to produce robust programs. Many of these issues are particularly relevant when creating bash scripts for administrative tasks.

For the bash script shown below, identify specific weaknesses from the point of view of robustness and defensive programming, and suggest approaches to address those weaknesses (you do not need to produce actual bash code to fix them). Sample runs of the script are also shown below.

Note: the "2> /dev/null" used below effectively suppresses stderr messages from command

#! /bin/bash

function menu()
{
   echo "The available actions are:"
   echo "   H - display your home directory and total disk utilization"
   echo "   I - display system status information"
   echo "   L - list the current directory location and content"
   echo "   M - display this menu"
   echo "   S - display the storage space used for the current directory (and subdirectories)"
   echo "   Q - quit"
}

function info()
{
   echo "Enter your command (any of H I L M Q S - M displays the full menu)"
   read cmd
   if [ $cmd = "H" ] ; then
      echo "The disk utilization stats for account " $USER " (home directory " $HOME ") are:"
      du -sh $HOME 2> /dev/null
   elif [ $cmd = "S" ] ; then
      echo "The disk storage stats for " $PWD " are:"
      du -sh . 2> /dev/null
   elif [ $cmd = "M" ] ; then
      menu
   elif [ $cmd = "L" ] ; then
      echo "The contents of " $PWD " are:"
      ls -aF
   elif [ $cmd = "Q" ] ; then
      echo "Bye!"
   elif [ $cmd = "I" ] ; then
      echo "The status of system " $HOSTNAME " is "
      uptime
   else
      echo "Invalid command entered: " $cmd
   fi
}

info

Enter your command (any of H I L M Q S - M displays the full menu) 
H 
The disk utilization stats for account  wesselsd  (home directory  /home/faculty/wesselsd ) are: 
2.0G	/home/faculty/wesselsd 

Enter your command (any of H I L M Q S - M displays the full menu) I The status of system owl is 11:08:02 up 36 days, 2:43, 6 users, load average: 0.13, 0.08, 0.02
Enter your command (any of H I L M Q S - M displays the full menu) L The contents of /otter/faculty/wesselsd/public_html/courses/csci265/exams/ThisYear/midt18 are: ./ ../ index.html q3.sh* typescript
Enter your command (any of H I L M Q S - M displays the full menu) M The available actions are: H - display your home directory and total disk utilization I - display system status information L - list the current directory location and content M - display this menu S - display the storage space used for the current directory (and subdirectories) Q - quit
Enter your command (any of H I L M Q S - M displays the full menu) Q Bye!
Enter your command (any of H I L M Q S - M displays the full menu) S The disk storage stats for /otter/faculty/wesselsd/public_html/courses/csci265/exams/ThisYear/midt18 are: 12K .
Enter your command (any of H I L M Q S - M displays the full menu) X Invalid command entered: X

Sample Solution

Lots of possible critiques here, some more important than others:
 - if user enters something like * then when it gets to the "Invalid command" output
   it actually displays the current directory contents, so either the user input
   should be sanitized or (at least) when displaying the variable it should be placed
   inside quotes (i.e. "$cmd")
 - to be more forgiving on input it should either accept both upper and lowercase
   commands or convert them all to a standard case before checking
 - redirecting some of the stderr output to /dev/null conceals potential problems
   from the user: the output should probably be captured and more appropriate messages
   delivered to the user as a result
 - the command output from other system commands are delivered to the user unfiltered,
   errors and all: it would probably be wise to capture/filter that
 - the prompts and error messages, and how to invoke menu, could be clearer
 - a retry/repeat option might be helpful, rather than making the user re-run the script
 - the script is entirely uncommented
 - a gui to better control interaction with the user might help

Question 3: Bash scripting [8]

Write a complete and correct bash function named "gitmakes" that meets the following specifications:

Advice: you can create/use one or more helper functions

Sample Solution

# helper function to process a single directory
function gitex()
{
   # bail out if no directory given (won't happen from gitmakes)
   if [ $# -ne 1 ] ; then
      echo "dir expected"
      return 0
   fi

   # grab the directory name, error check, and process
   local dir=$1

   # process iff it is an accessible directory
   if [ -d $dir ] && [ -r $dir ] && [ -x $dir ] ; then

      # check for git repository
      if [ -d "$dir"/.git ] ; then
         echo "$dir is the root of a git repository"
      fi

      # check for makefile
      if [ -f "$dir"/makefile ] ; then
         echo "$dir contains a makefile"
      fi

      # recurse into any subdirectories
      for subdir in "$dir"/* ; do
          if [ -d $subdir ] ; then
             gitex $subdir
          fi
      done

   # give error messages for invalid/inaccessible directories
   else
      echo "Error: $dir is not an accessible directory"
   fi
}

# gitmakes takes the list of directories and passes them one at a time to gitex
function gitmakes()
{
   for dir in $@ ; do
      gitex $dir
   done
}

Question 4: Specifications [8]

Suppose we needed to come up with a set of non-functional specifications for a text-messaging service, and for future verification purposes we need quantifiable/measurable specifications.

Provide a set of example specifications covering:

Sample Solution

Lots of possibilities here, but they have to be specifications covering the
    qualitative (not functional) aspects mentioned, and the specifications
    you give must be measurable, e.g.

availability: the system cannot be unavailable more than 3 hours per month,
   and never unavailable for more than 15 consecutive minutes

capacity: within the availability constraints above, the central servers
   should be capable of processing 10,000 messages per minute

accessibility: within the capacity and availability constraints listed above,
   the only acceptable reason for the system being unaccessible to the user
   is a third-party network failure somewhere between the user and our servers

reliability: 99.9% of all messages sent per month should be received,
   subject to the constraints listed above

data integrity: 99.9% of all messages received should arrive in an uncorrupted form

delivery speed: all messages received should arrive within 12 seconds of being sent,
    subject to the constraints listed above

Question 5: Life cycle models [8]

A test-driven software development process works as follows:

(i) Describe circumstances under which this would be a worthwhile process to follow.

(ii) Discuss the advantages and disadvantages of this process compared to an agile development process.

Sample Solution

Note that, compared to an agile process, this new (to us) process is more focused on
   passing specific relevant/representative test cases provided for us by the client,
   rather than on more general feedback/direction/requirements.  (The user isn't giving
   us requirements except in the form of test cases it must pass.)

(In reality, the test-driven-development is often used as an internal process,
   where someone in the development team comes up with the sequence of test cases
   based on conversations with the user, and the rest of the dev team has to
   code to pass the latest test plus all the others.)

In the form described, it is likely to be worthwhile when
 - the product is something that can be delivered bit by bit and still
   be useful (adding new functionality to what we've already built)
 - the client is good at providing representative test cases, but perhaps
   not so good at giving more generalized goals/feedback or a bigger picture
 - the developers are good at writing adaptable code, and modifying it to
   meet new objectives

Advantages compared to agile:
 - the developers have very clear pass/fail targets for each new test,
   they aren't waiting for less predictable feedback from the user(s)
 - the individual development cycles are probably quicker in general,
   since the devs are coding just to one specific test rather than more
   generalized goals/objectives

Disadvantages compared to agile:
 - the test-based nature is less suitable for generalized feedback, the
   client has to come up with test cases that demonstrate what they want,
   which the user might find challenging.
 - it might take more development cycles to arrive at what the user really
   wants compared to agile, simply because the number of tests needed to
   encapsulate all desired behaviour might be pretty large
 - as given, it assumes each test case is valid forever, whereas agile
   is more flexible, allowing the user to change their mind and toss out
   earlier ideas