Seite wählen

NETWAYS Blog

May I introduce the Rubocop

When you are into developing Ruby code, or even Ruby near stuff like Puppet modules, or Chef cookbooks, there is a nice tool you should have a look at.
The RuboCop can help you writing better Ruby code, it certainly did it for me.
In short words, RubyCop is a code analyzer that checks Ruby code against common style guidelines and tries to detect a lot of mistakes and errors that you might write into your code.
There are a lot of configuration options, and even an auto-correct functionality, that updates your code.

Simple usage

Either install the gem, or add it to your Gemfile:

gem 'rubocop', require: false

You can just run it without configuration, and it will look for all Ruby files in your work directory.

$ rubocop
Inspecting 19 files
....C............CC
Offenses:
lib/test/cli.rb:3:3: C: Missing top-level class documentation comment.
 class CLI
 ^^^^^
lib/test/cli.rb:36:1: C: Extra empty line detected at method body beginning.
lib/test/cli.rb:41:1: C: Extra empty line detected at block body beginning.
lib/test/cli.rb:45:4: C: Final newline missing.
end
bin/test:12:1: C: Missing space after #.
#api.login('username', 'Passw0rd') unless api.logged_in?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/test:15:3: C: Missing space after #.
 #puts response.code
 ^^^^^^^^^^^^^^^^^^^
bin/test:19:1: C: Missing space after #.
#session.save(file)
^^^^^^^^^^^^^^^^^^^
18 files inspected, 7 offenses detected

You can add it as a rake job to your Rakefile:

require 'rubocop/rake_task'
RuboCop::RakeTask.new
task default: [:spec, :rubocop]

And run the test via your rake tests:

$ rake
$ rake rubocop

Configuration galore

There are a lot of options to modify the behavior and expectations of RuboCop.
Here is a short example I used with recent Puppet module.

require: rubocop-rspec
AllCops:
  TargetRubyVersion: 1.9
  Include:
    - ./**/*.rb
  Exclude:
    - vendor/**/*
    - .vendor/**/*
    - pkg/**/*
    - spec/fixtures/**/*
# We don't use rspec in this way
RSpec/DescribeClass:
  Enabled: False
RSpec/ImplicitExpect:
  Enabled: False
# Example length is not necessarily an indicator of code quality
RSpec/ExampleLength:
  Enabled: False
RSpec/NamedSubject:
  Enabled: False

Where to go next

Debugging mit Docker

docker
Docker ist uns allen als leichtgewichtige Lösung bekannt mit deren Hilfe man Anwendungen in Containern bereitstellen kann. Ist man etwas kreativ, kann man mit Docker aber viel mehr „verbrechen“. So kann man beispielsweise Docker sehr gut zum debuggen von Applikationen verwenden.
Jetzt fragt ihr euch sicher: „Was ist den bei dem kaputt? Zum debuggen brauch ich in 90 % aller Fälle eine Konsole“. Aber warum den nicht!? Es ist zwar gegen die Idee von Docker, aber man kann damit natürlich auch einen kleine Debugging-Container mit SSH betreiben.
 
 
Hier ein kurzes Beispiel in Form eines Dockerfiles:
FROM debian:8.4
MAINTAINER $your_name $your_email


# install needed packages
RUN apt-get update && apt-get install -y openssh-server rsync rsnapshot vim git sudo ntpdate ethtool screen dnsutils shorewall curl unzip telnet net-tools ntp ntpdate


# prepare root account and login
RUN mkdir /var/run/sshd

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile


# prepare user
RUN groupadd -g 10000 $your_name
RUN useradd -g 10000 -u 10000 -s /bin/bash -m $your_name
RUN mkdir /home/$your_name/.ssh && chmod 750 /home/$your_name/.ssh && chown $your_name. /home/$your_name/.ssh
RUN echo "<$your_ssh_key>" > /home/$your_name/.ssh/authorized_keys && chmod 600 /home/$your_name/.ssh/authorized_keys && chown $your_name. /home/$your_name/.ssh/authorized_keys
RUN echo "$your_name ALL=NOPASSWD: ALL" > /etc/sudoers.d/$your_name && chmod 640 /etc/sudoers.d/$your_name


# map ssh port and run ssh
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

Wenn ihr jetzt alle $your_name durch euren Benutzernamen ersetzt (Variablen funktionieren bei Docker leider nicht in der RUN-Umgebung) erhaltet ihr ein aktuelles Debian 8.4 mit einem SSH Zugang. Dieses Dockerfile mit SSH kann man nun z. B. sehr einfach um Icinga2 Pakete erweitern. Etwas weiter gesponnen könnte man noch verschiedene Betriebssystemversionen oder die Auswahl Icinga2 Stable oder Snapshot mit einbauen.
Alles in allem erhält man einen sehr leichtgewichtigen Container der das Debuggen ermöglicht, der sehr schnell provisioniert ist und man mit der entsprechenden Storage Config sogar anwendungsspezifische Konfigurationen und Dateien mit schleppen kann.

Tobias Redel
Tobias Redel
Head of Professional Services

Tobias hat nach seiner Ausbildung als Fachinformatiker bei der Deutschen Telekom bei T-Systems gearbeitet. Seit August 2008 ist er bei NETWAYS, wo er in der Consulting-Truppe unsere Kunden in Sachen Open Source, Monitoring und Systems Management unterstützt. Insgeheim führt er jedoch ein Doppelleben als Travel-Hacker und renoviert, baut und bastelt als Heimwerker an allem was er finden kann.

Mocks und Stubs mit Mockery

Heute möchte ich euch das PHP-Framework „Mockery“ vorstellen. Wie dessen Name und der Titel dieses Blog-Post schon vermuten lassen, ist es damit möglich Mocks und Stubs (im Folgenden nur noch „Mock“) in/für PHP zu erstellen. Mockery arbeitet prinzipiell wunderbar mit z.B. PHPUnit zusammen und kollidiert nicht mit anderen Frameworks, jedoch gibt es gerade in dieser Kombination, für einen erfolgreichen Einsatz, einiges zu beachten.
Mit Mockery können fünf verschiedene Arten von Mocks erstellt werden. Die einfachste Art sind Mocks ohne Bezug zu jeglichen bereits existierenden Code-Bestandteilen. Mocks können jedoch auch von einem bestimmten Typ sein, sei es nun eine konkrete bzw. abstrakte Klasse oder ein Interface. Da Mocks standardmäßig alle Methoden einer Klasse maskieren, kann man sie als „partielle“ Mocks deklarieren wodurch nur ganz bestimmte Methoden maskiert werden. Statische Methoden und sogar Instanziierungen können mit Hilfe von „Alias-Mocks“ gemocked werden, sofern auto loading genutzt wird und die eigentlichen Klassen noch nicht geladen wurden. Selbst bereits existierende Mocks können erweitert werden und erben so alle Eigenschaften des Basis-Mocks.
Damit Mocks aber überhaupt erst sinnvoll verwendet werden können, muss definiert werden wie diese verwendet werden. Dies geschieht mit sogenannten „Expectations“. Eine solche Expectation besteht aus mindestens einem Methoden-Namen und optional ein oder mehreren Argument-Validatoren. Diese Validatoren bestimmen wie die Argumente, die die Methode erwartet, auszusehen haben. Entspricht etwas nicht den Erwartungen wird eine Ausnahme geworfen, was im Falle von PHPUnit zu einem fehlgeschlagenen Test führt.
Selbstverständlich kann man auch das Verhalten eines Mocks, mit sogenannten „Behaviour modifiers“, beeinflussen. Ob ein bestimmter Wert zurückgegeben, eine bestimmte Ausnahme geworfen, eine bestimmte Eigenschaft gesetzt oder die Methode nur eine bestimmte Anzahl oft (Nie?) aufgerufen werden soll, alles kein Problem für Mockery.
Ein besonders tolles Feature von Mockery, sind die „Demeter Chains“. Hiermit lassen sich fluid interfaces auf sehr einfache Art und Weise mocken:

$fritz = Mockery::mock(‚FischersFritz‘);
$fritz->shouldReceive(‚fischt->frische->fische‘);
$fritz->fischt()->frische()->fische();

Zu beachten ist hier, dass diese Form der Expectation nicht kompatibel mit der Methode getMock() ist:

// getMock() gibt nicht den Mock zurück. Dies ist leider kein bug.
$fritz = Mockery::mock(‚SomeFritz‘)->shouldReceive(‚fischt->frische->fische‘)->getMock();

Mockery hat jedoch auch seine Kehrseiten. So ist es z.B. inkompatibel mit dem Feature „backupStaticAttributes“ von PHPUnit, kann keine Mocks mit Zuständen und keine multiplen „Demeter Chains“ abbilden. Außerdem ist man z.T. gezwungen das „runInSeparateProcess“ Feature von PHPUnit zu verwenden, wenn man „Alias-Mocks“ einsetzt.
Im Großen und Ganzen bin ich sehr zufrieden mit Mockery, setze es gerne ein und kann es nur weiter empfehlen. Da ich allerdings nicht die vollständige Funktionalität von Mockery vorgestellt habe, lege ich jedem ans Herz einen Blick in die doch sehr umfangreiche und übersichtliche Dokumentation zu werfen.

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.