Skip to content

Instantly share code, notes, and snippets.

@mearns
Last active September 2, 2023 20:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mearns/a86286eace104c89c012 to your computer and use it in GitHub Desktop.
Save mearns/a86286eace104c89c012 to your computer and use it in GitHub Desktop.
A cheat sheet for server spec and rspec
<!DOCTYPE html >
<html>
<!-- This was hacked together by hand after python-markdown output the bulk of it.
Maybe someday I'll put together a better script to aut-generate this from markdown source. -->
<head>
<!-- github-markdown, plus github pygments -->
<style type='text/css'>
/* <![CDATA[ */
@font-face {
font-family: octicons-link;
src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
}
.markdown-body {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
color: #333;
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 16px;
line-height: 1.6;
word-wrap: break-word;
}
.markdown-body a {
background-color: transparent;
}
.markdown-body a:active,
.markdown-body a:hover {
outline: 0;
}
.markdown-body strong {
font-weight: bold;
}
.markdown-body h1 {
font-size: 2em;
margin: 0.67em 0;
}
.markdown-body img {
border: 0;
}
.markdown-body hr {
box-sizing: content-box;
height: 0;
}
.markdown-body pre {
overflow: auto;
}
.markdown-body code,
.markdown-body kbd,
.markdown-body pre {
font-family: monospace, monospace;
font-size: 1em;
}
.markdown-body input {
color: inherit;
font: inherit;
margin: 0;
}
.markdown-body html input[disabled] {
cursor: default;
}
.markdown-body input {
line-height: normal;
}
.markdown-body input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
.markdown-body table {
border-collapse: collapse;
border-spacing: 0;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body * {
box-sizing: border-box;
}
.markdown-body input {
font: 13px / 1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
.markdown-body a {
color: #4078c0;
text-decoration: none;
}
.markdown-body a:hover,
.markdown-body a:active {
text-decoration: underline;
}
.markdown-body hr {
height: 0;
margin: 15px 0;
overflow: hidden;
background: transparent;
border: 0;
border-bottom: 1px solid #ddd;
}
.markdown-body hr:before {
display: table;
content: "";
}
.markdown-body hr:after {
display: table;
clear: both;
content: "";
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: 15px;
margin-bottom: 15px;
line-height: 1.1;
}
.markdown-body h1 {
font-size: 30px;
}
.markdown-body h2 {
font-size: 21px;
}
.markdown-body h3 {
font-size: 16px;
}
.markdown-body h4 {
font-size: 14px;
}
.markdown-body h5 {
font-size: 12px;
}
.markdown-body h6 {
font-size: 11px;
}
.markdown-body blockquote {
margin: 0;
}
.markdown-body ul,
.markdown-body ol {
padding: 0;
margin-top: 0;
margin-bottom: 0;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: lower-roman;
}
.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
list-style-type: lower-alpha;
}
.markdown-body dd {
margin-left: 0;
}
.markdown-body code {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
}
.markdown-body pre {
margin-top: 0;
margin-bottom: 0;
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.markdown-body .select::-ms-expand {
opacity: 0;
}
.markdown-body .octicon {
font: normal normal normal 16px/1 octicons-link;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.markdown-body .octicon-link:before {
content: '\f05c';
}
.markdown-body:before {
display: table;
content: "";
}
.markdown-body:after {
display: table;
clear: both;
content: "";
}
.markdown-body>*:first-child {
margin-top: 0 !important;
}
.markdown-body>*:last-child {
margin-bottom: 0 !important;
}
.markdown-body a:not([href]) {
color: inherit;
text-decoration: none;
}
.markdown-body .anchor {
display: inline-block;
padding-right: 2px;
margin-left: -18px;
}
.markdown-body .anchor:focus {
outline: none;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: 1em;
margin-bottom: 16px;
font-weight: bold;
line-height: 1.4;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: #000;
vertical-align: middle;
visibility: hidden;
}
.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
visibility: visible;
}
.markdown-body h1 {
padding-bottom: 0.3em;
font-size: 2.25em;
line-height: 1.2;
border-bottom: 1px solid #eee;
}
.markdown-body h1 .anchor {
line-height: 1;
}
.markdown-body h2 {
padding-bottom: 0.3em;
font-size: 1.75em;
line-height: 1.225;
border-bottom: 1px solid #eee;
}
.markdown-body h2 .anchor {
line-height: 1;
}
.markdown-body h3 {
font-size: 1.5em;
line-height: 1.43;
}
.markdown-body h3 .anchor {
line-height: 1.2;
}
.markdown-body h4 {
font-size: 1.25em;
}
.markdown-body h4 .anchor {
line-height: 1.2;
}
.markdown-body h5 {
font-size: 1em;
}
.markdown-body h5 .anchor {
line-height: 1.1;
}
.markdown-body h6 {
font-size: 1em;
color: #777;
}
.markdown-body h6 .anchor {
line-height: 1.1;
}
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre {
margin-top: 0;
margin-bottom: 16px;
}
.markdown-body hr {
height: 4px;
padding: 0;
margin: 16px 0;
background-color: #e7e7e7;
border: 0 none;
}
.markdown-body ul,
.markdown-body ol {
padding-left: 2em;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markdown-body li>p {
margin-top: 16px;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: bold;
}
.markdown-body dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.markdown-body blockquote {
padding: 0 15px;
color: #777;
border-left: 4px solid #ddd;
}
.markdown-body blockquote>:first-child {
margin-top: 0;
}
.markdown-body blockquote>:last-child {
margin-bottom: 0;
}
.markdown-body table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all;
}
.markdown-body table th {
font-weight: bold;
}
.markdown-body table th,
.markdown-body table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
.markdown-body table tr {
background-color: #fff;
border-top: 1px solid #ccc;
}
.markdown-body table tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-body img {
max-width: 100%;
box-sizing: content-box;
background-color: #fff;
}
.markdown-body code {
padding: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin: 0;
font-size: 85%;
background-color: rgba(0,0,0,0.04);
border-radius: 3px;
}
.markdown-body code:before,
.markdown-body code:after {
letter-spacing: -0.2em;
content: "\00a0";
}
.markdown-body pre>code {
padding: 0;
margin: 0;
font-size: 100%;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.markdown-body .highlight {
margin-bottom: 16px;
}
.markdown-body .highlight pre,
.markdown-body pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border-radius: 3px;
}
.markdown-body .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdown-body pre {
word-wrap: normal;
}
.markdown-body pre code {
display: inline;
max-width: initial;
padding: 0;
margin: 0;
overflow: initial;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
.markdown-body pre code:before,
.markdown-body pre code:after {
content: normal;
}
.markdown-body kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: solid 1px #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb;
}
.markdown-body .pl-c {
color: #969896;
}
.markdown-body .pl-c1,
.markdown-body .pl-s .pl-v {
color: #0086b3;
}
.markdown-body .pl-e,
.markdown-body .pl-en {
color: #795da3;
}
.markdown-body .pl-s .pl-s1,
.markdown-body .pl-smi {
color: #333;
}
.markdown-body .pl-ent {
color: #63a35c;
}
.markdown-body .pl-k {
color: #a71d5d;
}
.markdown-body .pl-pds,
.markdown-body .pl-s,
.markdown-body .pl-s .pl-pse .pl-s1,
.markdown-body .pl-sr,
.markdown-body .pl-sr .pl-cce,
.markdown-body .pl-sr .pl-sra,
.markdown-body .pl-sr .pl-sre {
color: #183691;
}
.markdown-body .pl-v {
color: #ed6a43;
}
.markdown-body .pl-id {
color: #b52a1d;
}
.markdown-body .pl-ii {
background-color: #b52a1d;
color: #f8f8f8;
}
.markdown-body .pl-sr .pl-cce {
color: #63a35c;
font-weight: bold;
}
.markdown-body .pl-ml {
color: #693a17;
}
.markdown-body .pl-mh,
.markdown-body .pl-mh .pl-en,
.markdown-body .pl-ms {
color: #1d3e81;
font-weight: bold;
}
.markdown-body .pl-mq {
color: #008080;
}
.markdown-body .pl-mi {
color: #333;
font-style: italic;
}
.markdown-body .pl-mb {
color: #333;
font-weight: bold;
}
.markdown-body .pl-md {
background-color: #ffecec;
color: #bd2c00;
}
.markdown-body .pl-mi1 {
background-color: #eaffea;
color: #55a532;
}
.markdown-body .pl-mdr {
color: #795da3;
font-weight: bold;
}
.markdown-body .pl-mo {
color: #1d3e81;
}
.markdown-body kbd {
display: inline-block;
padding: 3px 5px;
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: solid 1px #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb;
}
.markdown-body .task-list-item {
list-style-type: none;
}
.markdown-body .task-list-item+.task-list-item {
margin-top: 3px;
}
.markdown-body .task-list-item input {
margin: 0 0.35em 0.25em -1.6em;
vertical-align: middle;
}
.markdown-body :checked+.radio-label {
z-index: 1;
position: relative;
border-color: #4078c0;
}
.codehilite .hll { background-color: #ffffcc }
.codehilite .c { color: #999988; font-style: italic } /* Comment */
.codehilite .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.codehilite .k { color: #000000; font-weight: bold } /* Keyword */
.codehilite .o { color: #000000; font-weight: bold } /* Operator */
.codehilite .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */
.codehilite .c1 { color: #999988; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.codehilite .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.codehilite .ge { color: #000000; font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #aa0000 } /* Generic.Error */
.codehilite .gh { color: #999999 } /* Generic.Heading */
.codehilite .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.codehilite .go { color: #888888 } /* Generic.Output */
.codehilite .gp { color: #555555 } /* Generic.Prompt */
.codehilite .gs { font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #aaaaaa } /* Generic.Subheading */
.codehilite .gt { color: #aa0000 } /* Generic.Traceback */
.codehilite .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
.codehilite .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.codehilite .m { color: #009999 } /* Literal.Number */
.codehilite .s { color: #d01040 } /* Literal.String */
.codehilite .na { color: #008080 } /* Name.Attribute */
.codehilite .nb { color: #0086B3 } /* Name.Builtin */
.codehilite .nc { color: #445588; font-weight: bold } /* Name.Class */
.codehilite .no { color: #008080 } /* Name.Constant */
.codehilite .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */
.codehilite .ni { color: #800080 } /* Name.Entity */
.codehilite .ne { color: #990000; font-weight: bold } /* Name.Exception */
.codehilite .nf { color: #990000; font-weight: bold } /* Name.Function */
.codehilite .nl { color: #990000; font-weight: bold } /* Name.Label */
.codehilite .nn { color: #555555 } /* Name.Namespace */
.codehilite .nt { color: #000080 } /* Name.Tag */
.codehilite .nv { color: #008080 } /* Name.Variable */
.codehilite .ow { color: #000000; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
.codehilite .mf { color: #009999 } /* Literal.Number.Float */
.codehilite .mh { color: #009999 } /* Literal.Number.Hex */
.codehilite .mi { color: #009999 } /* Literal.Number.Integer */
.codehilite .mo { color: #009999 } /* Literal.Number.Oct */
.codehilite .sb { color: #d01040 } /* Literal.String.Backtick */
.codehilite .sc { color: #d01040 } /* Literal.String.Char */
.codehilite .sd { color: #d01040 } /* Literal.String.Doc */
.codehilite .s2 { color: #d01040 } /* Literal.String.Double */
.codehilite .se { color: #d01040 } /* Literal.String.Escape */
.codehilite .sh { color: #d01040 } /* Literal.String.Heredoc */
.codehilite .si { color: #d01040 } /* Literal.String.Interpol */
.codehilite .sx { color: #d01040 } /* Literal.String.Other */
.codehilite .sr { color: #009926 } /* Literal.String.Regex */
.codehilite .s1 { color: #d01040 } /* Literal.String.Single */
.codehilite .ss { color: #990073 } /* Literal.String.Symbol */
.codehilite .bp { color: #999999 } /* Name.Builtin.Pseudo */
.codehilite .vc { color: #008080 } /* Name.Variable.Class */
.codehilite .vg { color: #008080 } /* Name.Variable.Global */
.codehilite .vi { color: #008080 } /* Name.Variable.Instance */
.codehilite .il { color: #009999 } /* Literal.Number.Integer.Long */
/* ]]> */
</style>
<style type='text/css'>
/* <![CDATA[ */
.codehilite {
page-break-inside: avoid;
page-break-before: avoid;
page-break-after: auto;
break-inside: avoid;
break-before: avoid;
break-after: auto;
}
h1, h2, h3, h4, h5 {
page-break-after: avoid;
break-after: avoid;
page-break-before: auto;
break-before: auto;
}
section.no-break {
page-break-inside: avoid;
break-inside: avoid;
}
#content {
column-count: 2;
-moz-column-count: 2;
-moz-column-gap: 2.5em;
-moz-column-rule: 1px solid #eee;
}
.markdown-body h1 {
border-bottom-color: black;
}
.markdown-body h2 {
border-bottom: 4px solid black;
}
.markdown-body h3 {
border-bottom: 2px solid black;
}
@media print {
.markdown-body pre {
background-color: #ddd;
border: 1px solid #999;
}
#content {
-moz-column-rule: 1px solid #333;
}
}
/* ]]> */
</style>
</head>
<body class='markdown-body'>
<h1>Serverspec and RSpec Cheat Sheet</h1>
<div id='content'>
<h2>Assertions</h2>
<ul>
<li><code>should</code> means "assert true".</li>
<li><code>should_not</code> means "assert false".</li>
</ul>
<h2>Resources</h2>
<p><a href="http://serverspec.org/resource_types.html">http://serverspec.org/resource_types.html</a></p>
<section class='no-break'>
<h3>file</h3>
<p>Files, directories, and devices.</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">file</span><span class="p">(</span><span class="s1">&#39;/path/to/file&#39;</span><span class="p">)</span> <span class="k">do</span>
<span class="c1">#INode type</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_file</span> <span class="p">}</span> <span class="c1"># or be_directory, or be_symlink</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">exist</span> <span class="p">}</span>
<span class="c1">#Permissions</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_owned_by</span> <span class="s1">&#39;username&#39;</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_grouped_into</span> <span class="s1">&#39;groupname&#39;</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_mode</span> <span class="mi">440</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_readable</span> <span class="p">}</span> <span class="c1"># or be_writable or be_executable</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_readable</span><span class="o">.</span><span class="n">by</span><span class="p">(</span><span class="s1">&#39;owner&#39;</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># or &#39;group&#39; or &#39;others&#39;</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_readable</span><span class="o">.</span><span class="n">by_user</span><span class="p">(</span><span class="s1">&#39;username&#39;</span><span class="p">)</span> <span class="p">}</span>
<span class="c1">#Links</span>
<span class="k">if</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_linked_to</span> <span class="s1">&#39;/path/to/target&#39;</span> <span class="p">}</span>
<span class="c1">#Contents</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:md5sum</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">eq</span> <span class="s1">&#39;...&#39;</span> <span class="p">}</span> <span class="c1"># or, and rspec matcher</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:sha256sum</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">eq</span> <span class="s1">&#39;...&#39;</span> <span class="p">}</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:size</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="o">&lt;</span> <span class="mi">1024</span> <span class="p">}</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:content</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">match</span> <span class="sr">/some pattern/</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>user</h3>
<p>System users.</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">user</span><span class="p">(</span><span class="s1">&#39;username&#39;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">exist</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">belong_to_group</span> <span class="s1">&#39;group&#39;</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">have_home_directory</span> <span class="s1">&#39;/home/username&#39;</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">have_login_shell</span> <span class="s1">&#39;/bin/bash&#39;</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">have_authorized_key</span> <span class="s1">&#39;ssh-rsa ABCD... user@hostname&#39;</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>group</h3>
<p>System user groups.</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">group</span><span class="p">(</span><span class="s1">&#39;groupname&#39;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">exist</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>packages</h3>
<p>Software packages installed on the system.</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">package</span><span class="p">(</span><span class="s1">&#39;httpd&#39;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_installed</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
<p>Select based on operating system:</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">package</span><span class="p">(</span><span class="s1">&#39;httpd&#39;</span><span class="p">),</span> <span class="ss">:if</span> <span class="o">=&gt;</span> <span class="n">os</span><span class="o">[</span><span class="ss">:family</span><span class="o">]</span> <span class="o">==</span> <span class="s1">&#39;redhat&#39;</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_installed</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">describe</span> <span class="n">package</span><span class="p">(</span><span class="s1">&#39;apache2&#39;</span><span class="p">),</span> <span class="ss">:if</span> <span class="o">=&gt;</span> <span class="n">os</span><span class="o">[</span><span class="ss">:family</span><span class="o">]</span> <span class="o">==</span> <span class="s1">&#39;ubuntu&#39;</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_installed</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>port</h3>
<p>Network ports</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">port</span><span class="p">(</span><span class="mi">80</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_listening</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>service</h3>
<p>Installed services.</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">service</span><span class="p">(</span><span class="s1">&#39;httpd&#39;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_running</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_enabled</span> <span class="p">}</span> <span class="c1"># enabled to start when the OS boots.</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>process</h3>
<p>Currently running processes.</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">process</span><span class="p">(</span><span class="s2">&quot;memchached&quot;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_running</span> <span class="p">}</span>
<span class="c1"># parameters from ps, see `man ps(1)`, under &quot;STANDARD FORMAT SPECIFIERS&quot;</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:user</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">eq</span> <span class="s1">&#39;root&#39;</span> <span class="p">}</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:args</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">match</span> <span class="sr">/-c 32000\b/</span> <span class="p">}</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:nice</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="o">&gt;</span> <span class="mi">10</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>command</h3>
<p>Run arbitrary commands and check the results.</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">command</span><span class="p">(</span><span class="s1">&#39;ls -al /&#39;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:stdout</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">match</span> <span class="sr">/some pattern/</span> <span class="p">}</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:stderr</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_empty</span> <span class="p">}</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:exit_status</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">eq</span> <span class="mi">0</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>host</h3>
<p>Hosts on the network</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="n">host</span><span class="p">(</span><span class="s1">&#39;example.org&#39;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_resolvable</span> <span class="p">}</span>
<span class="c1"># address</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:ipaddress</span><span class="p">)</span> <span class="p">{</span> <span class="n">should</span> <span class="n">match</span> <span class="sr">/192\.168\.10\.10/</span> <span class="p">}</span> <span class="c1"># could be IPv4 or IPv6</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:ipv4_address</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="n">its</span><span class="p">(</span><span class="ss">:ipv6_address</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="c1"># reachability</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_reachable</span> <span class="p">}</span> <span class="c1"># ping</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_reachable</span><span class="o">.</span><span class="n">with</span><span class="p">(</span>
<span class="ss">:port</span> <span class="o">=&gt;</span> <span class="mi">53</span><span class="p">,</span> <span class="c1"># required parameter</span>
<span class="c1"># Optional params (default values shown)</span>
<span class="ss">:proto</span> <span class="o">=&gt;</span> <span class="s1">&#39;tcp&#39;</span><span class="p">,</span> <span class="c1"># or &#39;udp&#39;</span>
<span class="ss">:timeout</span> <span class="o">=&gt;</span> <span class="mi">5</span> <span class="c1"># in seconds.</span>
<span class="p">)}</span>
<span class="k">end</span>
</pre></div>
</section>
<h2>Matchers (rspec)</h2>
<p><a href="https://www.relishapp.com/rspec/rspec-expectations/v/3-4/docs/built-in-matchers"> https://www.relishapp.com/rspec/rspec-expectations/v/3-4/docs/built-in-matchers </a></p>
<p>To try these outside of a serverspec test, you'll need to <code>require 'RSpec'</code>,
and replace <code>describe</code> with <code>RSpec.describe</code>.</p>
<section class='no-break'>
<h3>For strings</h3>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="s1">&#39;foobar&#39;</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">eq</span> <span class="s1">&#39;foobar&#39;</span> <span class="p">}</span> <span class="c1"># match using == operator</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">match</span> <span class="sr">/ooba/</span> <span class="p">}</span> <span class="c1"># match using regex, anywhere in string.</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should_not</span> <span class="n">match</span> <span class="sr">/^ooba$/</span> <span class="p">}</span> <span class="c1"># anchor regex</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should_not</span> <span class="n">be_empty</span> <span class="p">}</span> <span class="c1"># test for empty string: &quot;&quot;</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">start_with</span><span class="p">(</span><span class="s1">&#39;fo&#39;</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">end_with</span><span class="p">(</span><span class="s1">&#39;bar&#39;</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_a</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>For numbers</h3>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="mi">10</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">eq</span> <span class="mi">10</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="o">==</span> <span class="mi">10</span> <span class="p">}</span> <span class="c1"># same as above.</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="o">&lt;</span> <span class="mi">20</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="o">&lt;=</span> <span class="mi">10</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="o">&gt;=</span> <span class="mi">9</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_within</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="mi">9</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_within</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">of</span><span class="p">(</span><span class="mi">11</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_a</span><span class="p">(</span><span class="no">Numeric</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># also consider: Float, Integer</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_an_instance_of</span><span class="p">(</span><span class="no">Fixnum</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># Direct class, no higher</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>For arrays</h3>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="o">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="o">]</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should_not</span> <span class="n">be_empty</span> <span class="p">}</span> <span class="c1"># test for empty list: []</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="kp">include</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># membership test</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should_not</span> <span class="kp">include</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">all</span><span class="p">(</span> <span class="n">be_an</span><span class="p">(</span><span class="nb">Integer</span><span class="p">)</span> <span class="p">)</span> <span class="p">}</span> <span class="c1"># apply matcher to all elements</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">all</span><span class="p">(</span> <span class="n">be_an</span><span class="p">(</span><span class="nb">Integer</span><span class="p">)</span><span class="o">.</span><span class="n">and</span> <span class="n">be</span> <span class="o">&lt;</span> <span class="mi">10</span> <span class="p">)</span> <span class="p">}</span> <span class="c1"># conjunction</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">start_with</span><span class="p">(</span><span class="o">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="o">]</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">end_with</span><span class="p">(</span><span class="o">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="o">]</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_an</span><span class="p">(</span><span class="nb">Array</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>For hashes</h3>
<div class="codehilite"><pre><span></span><span class="n">describe</span> <span class="p">({</span> <span class="ss">:a</span> <span class="o">=&gt;</span> <span class="s1">&#39;A&#39;</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=&gt;</span> <span class="mi">2</span> <span class="p">})</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">have_key</span><span class="p">(</span><span class="ss">:a</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="kp">include</span><span class="p">(</span><span class="ss">:a</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># same as above</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="kp">include</span><span class="p">(</span><span class="ss">:b</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># test for presence of key and the value it maps to.</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should_not</span> <span class="kp">include</span><span class="p">(</span><span class="ss">:b</span> <span class="o">=&gt;</span> <span class="mi">3</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should_not</span> <span class="kp">include</span><span class="p">(</span><span class="ss">:c</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_a</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>The general purpose <code>satisfy</code> matcher</h3>
<div class="codehilite"><pre><span></span><span class="n">describe</span><span class="p">(</span><span class="mi">3</span><span class="o">.</span><span class="mi">14159</span><span class="p">)</span> <span class="k">do</span>
<span class="c1"># Passes as long as the block returns true.</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">satisfy</span> <span class="p">{</span> <span class="o">|</span><span class="n">uut</span><span class="o">|</span>
<span class="n">uut</span><span class="o">.</span><span class="n">kind_of?</span><span class="p">(</span><span class="no">Numeric</span><span class="p">)</span> <span class="ow">and</span> <span class="n">uut</span> <span class="o">&gt;</span> <span class="mi">3</span> <span class="ow">and</span> <span class="n">uut</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="o">.</span><span class="mi">2</span>
<span class="p">}}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>Combining expectations (<code>and</code>, <code>or</code>)</h3>
<div class="codehilite"><pre><span></span><span class="n">describe</span><span class="p">(</span><span class="s2">&quot;thunder&quot;</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;thun&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">and</span> <span class="n">end_with</span><span class="p">(</span><span class="s2">&quot;der&quot;</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;won&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">or</span> <span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;thun&quot;</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="p">(</span><span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;won&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">or</span> <span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;thun&quot;</span><span class="p">))</span><span class="o">.</span><span class="n">and</span> <span class="n">end_with</span><span class="p">(</span><span class="s2">&quot;der&quot;</span><span class="p">)</span> <span class="p">}</span>
<span class="c1"># with line breaks</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="p">(</span>
<span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;won&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">or</span> <span class="p">\</span>
<span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;thun&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">or</span> <span class="p">\</span>
<span class="n">start_with</span><span class="p">(</span><span class="s2">&quot;pon&quot;</span><span class="p">)</span>
<span class="p">)</span><span class="o">.</span><span class="n">and</span> <span class="p">(</span>
<span class="n">end_with</span><span class="p">(</span><span class="s2">&quot;der&quot;</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
<section class='no-break'>
<h3>Defining custom matchers</h3>
<div class="codehilite"><pre><span></span><span class="no">RSpec</span><span class="o">::</span><span class="no">Matchers</span><span class="o">.</span><span class="n">define</span> <span class="ss">:be_multiple_of</span> <span class="k">do</span> <span class="o">|</span><span class="n">expected</span><span class="o">|</span>
<span class="n">match</span> <span class="k">do</span> <span class="o">|</span><span class="n">actual</span><span class="o">|</span>
<span class="n">actual</span> <span class="o">%</span> <span class="n">expected</span> <span class="o">==</span> <span class="mi">0</span>
<span class="k">end</span>
<span class="c1"># optional, override description</span>
<span class="n">description</span> <span class="k">do</span>
<span class="s2">&quot;be multiple of </span><span class="si">#{</span><span class="n">expected</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">end</span>
<span class="c1"># optionally, override failure message:</span>
<span class="n">failure_message</span> <span class="k">do</span> <span class="o">|</span><span class="n">actual</span><span class="o">|</span>
<span class="s2">&quot;expected that </span><span class="si">#{</span><span class="n">actual</span><span class="si">}</span><span class="s2"> would be a multiple of </span><span class="si">#{</span><span class="n">expected</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">end</span>
<span class="c1"># optionally, override failure message when negated:</span>
<span class="n">failure_message_when_negated</span> <span class="k">do</span> <span class="o">|</span><span class="n">actual</span><span class="o">|</span>
<span class="s2">&quot;expected that </span><span class="si">#{</span><span class="n">actual</span><span class="si">}</span><span class="s2"> would not be a multiple of </span><span class="si">#{</span><span class="n">expected</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Example:</p>
<div class="codehilite"><pre><span></span><span class="n">describe</span><span class="p">(</span><span class="mi">9</span><span class="p">)</span> <span class="k">do</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_multiple_of</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="p">}</span>
<span class="c1">#Deliberate failures</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should</span> <span class="n">be_multiple_of</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="p">{</span> <span class="n">should_not</span> <span class="n">be_multiple_of</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
</pre></div>
</section>
</div>
</body>
</html>

Serverspec and RSpec Cheat Sheet

Assertions

  • should means "assert true".
  • should_not means "assert false".

Resources

http://serverspec.org/resource_types.html

file

Files, directories, and devices.

describe file('/path/to/file') do
  
  #INode type
  it { should be_file }       # or be_directory, or be_symlink
  it { should exist }
  
  #Permissions
  it { should be_owned_by 'username' }
  it { should be_grouped_into 'groupname' }
  
  it { should be_mode 440 }
  
  it { should be_readable }               # or be_writable or be_executable
  it { should be_readable.by('owner') }   # or 'group' or 'others'
  it { should be_readable.by_user('username') }
  
  #Links
  if { should be_linked_to '/path/to/target' }
  
  #Contents
  its(:md5sum)    { should eq '...' }    # or, and rspec matcher
  its(:sha256sum) { should eq '...' }
  its(:size)      { should < 1024 }
  its(:content)   { should match /some pattern/ }
  
end

user

System users.

describe user('username') do
  it { should exist }
  it { should belong_to_group 'group' }
  it { should have_home_directory '/home/username' }
  it { should have_login_shell '/bin/bash' }
  it { should have_authorized_key 'ssh-rsa ABCD... user@hostname' }
end

group

System user groups.

describe group('groupname') do
  it { should exist }
end

packages

Software packages installed on the system.

describe package('httpd') do
  it { should be_installed }
end

Select based on operating system:

describe package('httpd'), :if => os[:family] == 'redhat' do
  it { should be_installed }
end

describe package('apache2'), :if => os[:family] == 'ubuntu' do
  it { should be_installed }
end

port

Network ports

describe port(80) do
  it { should be_listening }
end

service

Installed services.

describe service('httpd') do
  it { should be_running }
  it { should be_enabled }      # enabled to start when the OS boots.
end

process

Currently running processes.

describe process("memchached") do
  it { should be_running }
  
  # parameters from ps, see `man ps(1)`, under "STANDARD FORMAT SPECIFIERS"
  its(:user) { should eq 'root' }
  its(:args) { should match /-c 32000\b/ }
  its(:nice) { should > 10 }
end

command

Run arbitrary commands and check the results.

describe command('ls -al /') do
  its(:stdout) { should match /some pattern/ }
  its(:stderr) { should be_empty }
  its(:exit_status) { should eq 0 }
end

host

Hosts on the network

describe host('example.org') do
  it { should be_resolvable }
  
  # address
  its(:ipaddress) { should match /192\.168\.10\.10/ }     # could be IPv4 or IPv6
  its(:ipv4_address) { ... }
  its(:ipv6_address) { ... }

  # reachability
  it { should be_reachable }        # ping
  it { should be_reachable.with(
        :port => 53,                # required parameter
        # Optional params (default values shown)
        :proto => 'tcp',            # or 'udp'
        :timeout => 5               # in seconds.
  )}
end

Matchers (rspec)

https://www.relishapp.com/rspec/rspec-expectations/v/3-4/docs/built-in-matchers

To try these outside of a serverspec test, you'll need to require 'RSpec', and replace describe with RSpec.describe.

For strings

describe 'foobar' do
  it { should eq 'foobar' }         # match using == operator
  it { should match /ooba/ }        # match using regex, anywhere in string.
  it { should_not match /^ooba$/ }  # anchor regex
  it { should_not be_empty }        # test for empty string: ""

  it { should start_with('fo') }
  it { should end_with('bar') }

  it { should be_a(String) }
end

For numbers

describe 10 do
  it { should eq 10 }
  it { should == 10 }             # same as above.
  it { should < 20 }
  it { should <= 10 }
  it { should > 0 }
  it { should >= 9 }

  it { should be_within(2).of(9) }
  it { should be_within(2).of(11) }

  it { should be_a(Numeric) }     # also consider: Float, Integer
  it { should be_an_instance_of(Fixnum) } # Direct class, no higher
end

For arrays

describe [1, 2, 3] do
  it { should_not be_empty }      # test for empty list: []

  it { should include(2) }        # membership test
  it { should_not include(0) }

  it { should all( be_an(Integer) ) }             # apply matcher to all elements
  it { should all( be_an(Integer).and be < 10 ) } # conjunction

  it { should start_with([1,2]) }
  it { should end_with([2,3]) }

  it { should be_an(Array) }
end

For hashes

describe ({ :a => 'A', :b => 2 }) do
  it { should have_key(:a) }
  it { should include(:a) }       # same as above
  it { should include(:b => 2) }  # test for presence of key and the value it maps to.
  it { should_not include(:b => 3) }
  it { should_not include(:c => 2) }

  it { should be_a(Hash) }
end

The general purpose satisfy matcher

describe(3.14159) do
  # Passes as long as the block returns true.
  it { should satisfy { |uut|
    uut.kind_of?(Numeric) and uut > 3 and uut < 3.2
  }}
end

Combining expectations (and, or)

describe("thunder") do
  it { should start_with("thun").and end_with("der") }
  it { should start_with("won").or start_with("thun") }
  it { should (start_with("won").or start_with("thun")).and end_with("der") }

  # with line breaks
  it { should (
      start_with("won").or \
      start_with("thun").or \
      start_with("pon")
    ).and (
      end_with("der")
    )
  }
end

Defining custom matchers

RSpec::Matchers.define :be_multiple_of do |expected|
  match do |actual|
    actual % expected == 0
  end

  # optional, override description
  description do
    "be multiple of #{expected}"
  end

  # optionally, override failure message:
  failure_message do |actual|
    "expected that #{actual} would be a multiple of #{expected}"
  end

  # optionally, override failure message when negated:
  failure_message_when_negated do |actual|
    "expected that #{actual} would not be a multiple of #{expected}"
  end
end

describe(9) do
  it { should be_multiple_of(3) }

  #Deliberate failures
  it { should be_multiple_of(2) }
  it { should_not be_multiple_of(3) }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment