1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
|
\chapter{Testing}
\epigraph{Testing shows the presence, not the absence of
bugs.}{\textit{Dijkstra}\cite{dijkstra69}}
\section{Unit testing}
The \verb+nose+\cite{pylib:nose} testing framework was used to
write unit tests for the functions and classes part of the
\verb+combox.config+, \verb+combox.crypto+, \verb+combox.events+,
\verb+combox.file+, \verb+combox.silo+ \verb+combox._version+
modules. Unit tests were not written for \verb+combox.cbox+,
\verb+combox.gui+, \verb+combox.combox.log+ modules.
Unit tests for combox become reality by pure serendipity. During the
time, when I started working on combox, I was learning to use the
\verb+nose+ library to unit test python code. Since, \verb+combox+ was
being written in python, I started making it a norm to write unit
tests for functions and classes in combox modules.
As mentioned before, unit tests were not written for some modules
either because it would make no sense to write one (for the
\verb+combox.cbox+ module, for instance, which basically uses
functions and classes defined in other modules to run combox) or it
was not clear how to write unit tests it (the \verb+combox.gui+
contains just the \verb+ComboxConfigDialog+ a graphical front-end
which uses the configuration function defined in the
\verb+combox.config+ module to complete the combox configuration based
on the user input).
It must be noted here that pure Test Driven Development (TDD) was not
observed -- most of the time the function/class was written before the
its corresponding test was written.
\subsection{Benefits}
While writing unit tests definitely increased the time to write a
particular feature, it enabled me to immediately check if a feature
worked as it should for the given use case or given set of inputs.
With the benefit of hindsight, unit tests greatly helped in testing
the compatibility of combox on OSX. Before the \verb+v0.1.0+ release,
combox's node directory monitor always assumed that a file's first
shard (\verb+shard0+) is always available; while this assumption did
not create any problems on GNU/Linux, on OS X, this assumption made
the node directory monitor to behave erratically -- this issue (bug
\#4\cite{combox-issue-tracker} was immediately found when the unit
tests were run for the first time on OS X. Another instance where unit
tests helped was just before the \verb+v0.2.0+ release; major changes,
including the introduction of file locks in the
\verb+ComboxDirMonitor+, were made to the \verb+combox.events+. When
the unit tests were run OS X, two tests failed, revealing a difference
in behavior of watchdog\cite{pylib:watchdog} on GNU/Linux and OS X on
file creation\cite{combox-wd-fix}; without unit tests, there is a high
probability that this bug would never have been found by now.
\subsection{Caveats}
Unit tests are helpful in testing the correctness of a feature for
\verb+N+ number of use cases but it does not necessarily mean the
written feature correctly behaves for use cases that the author of the
feature did not consider or did not think about while writing the
respective feature. As Dijkstra correctly observed:
Unit tests failed to reveal bugs \#4, \#5 \#6 \#7 \#5 \#10
\#11\cite{combox-issue-tracker}; these bugs were found when manually
testing combox.
\section{Manual testing}
The unit tests for the \verb+combox.events+ module test the
correctness of the \verb+ComboxDirMonitor+ and \verb+NodeDirMonitor+
independently; in order to comprehensively test the correctness of
both \verb+ComboxDirMonitor+ and \verb+NodeDirMonitor+, it was
required to manually test combox running on more than one computer. As
you'll see in the following subsections, several bugs were found and
fixed while doing manual testing.
Three different types of setups were used to test combox. The first
kind of setup has two GNU/Linux machines each using combox to sync
files between each other with Dropbox and Google Drive being the
nodes; the second kind of setup has a GNU/Linux machine and a OS X
machine each using combox to sync files between each other with
Dropbox and Google Drive being the nodes; the third kind of setup has
a GNU/Linux machine and OS X machine each using combox to sync files
between each other with Dropbox, Google Drive and a USB stick as
nodes.
\subsection{General setup and notes}
\begin{itemize}
\item On the GNU/Linux machines, the official Dropbox client was used
to sync the Dropbox node directory to Dropbox'
servers. \verb+rclone+\cite{program:rclone} was used to sync the
Google Drive node directory to Google Drive' servers;At the time of
testing, Google Drive did not have client for GNU/Linux.
\item On OS X, the official Dropbox client was used to sync the
Dropbox node directory to Dropbox's servers; the official Google
Drive client was used to sync the Google Drive node directory to
Google Driver' servers.
\item Since combox is extremely event-driven, combox must be started
before the Dropbox and Google Drive clients start syncing their
respective directories (nodes).
\end{itemize}
\subsection{Testing on two GNU/Linux machines}
combox was run to two GNU/Linux machines and a file was alternatively
created/modified/renamed/deleted on an of the GNU/Linux machine and it
was verified if the respective file was also
created/modified/renamed/deleted on the other GNU/Linux machine. One
of the GNU/Linux machine (\verb+lyra)+ was a virtual machine running
Debian GNU/Linux stable (version 8.x); the other GNU/Linux machine
(\verb+grus+) was a physical machine running Debian GNU/Linux
testing. The node directories to scatter the files' shards were the
Dropbox directory and Google Drive directory. The official Dropbox
client was used to automatically sync files from the Dropbox directory
to the Dropbox' server; \verb+rclone+\cite{program:rclone} was used to
sync files from Google Drive directory to Google Drive' server.
\subsubsection{Issues found}\label{ch-5-2gnus-issues}
\begin{itemize}
\item Some editors, especially on POSIX complaint systems, create
backup version of the file being edited. combox was detecting this
backup file as a ``new file'' and it split it into shards, encrypted
the shards and scattered the shards across the node directories. The
right thing for combox to do was to ignore these backup files and do
nothing about them. This issue was fixed on
\verb+2015-09-29+\cite{combox-issue-tracker}. Now the
\verb+ComboxDirMonitor+, on a ``file created'' or ``file modified''
event, returns from the \verb+on_created+ or \verb+on_modified+
callback when it finds that the file is a backup/temporary file.
\item Dropbox client maintains the \verb+.dropbox.cache+ directory
under the root of the Dropbox directory.
\begin{itemize}
\item When a file (shard) was created on another computer, the
Dropbox client pulls the new file (shard) to this computer into
\verb+.dropbox.cache+ as a temporary file and then moves the new
file (shard) to its respective location with the appropriate name.
\item When a file (shard) was modified on another computer, the
Dropbox client pulls the modified file (shard) to this computer
into the \verb+.dropbox.cache+ as a temporary file; moves the old
version of the file (shard) under the Dropbox directory into the
\verb+.dropbox.cache+; finally moves the updated copy of the file,
stored as a temporary file, into the Dropbox directory to its
respective location with the appropriate name.
\item When a file (shard) was deleted on another computer, the
Dropbox client moves the delete file into the
\verb+.dropbox.cache+ directory on this computer.
\end{itemize}
All of the above behavior of the Dropbox client epically broke
combox. Commits \verb+3d714c5+ to
\verb+6e1133f+\cite{git:dropbox-fix} fixed combox by making it aware
of Dropbox's client behavior.
\end{itemize}
\subsubsection{Demo}
Demo of combox being used on two GNU/Linux machines can be viewed at
\url{https://ricketyspace.net/combox/combox-2-gnus.webm}.
\verb+lyra+ (virtual machine) and \verb+grus+ (bare-metal) are the two
GNU/Linux machines being used for the demo.
Description of what happens in the demo follows:
- (lyra) install combox.
- (lyra) run combox (test mode).
- (lyra) create file \verb+walden.pond+ with content ``It must be
beautiful there''.
- (lyra) sync Google Drive using \verb+rclone+.
- (grus) sync Google Drive using \verb+rclone+.
- (grus) git pull latest copy of combox.
- (grus) install combox
- (grus) run combox (testing mode).
- (grus) verify that \verb+walden.pond+ was create on this machine.
- (grus) append 'Peaceful too.' to \verb+walden.pond+.
- (grus) sync Google Drive using \verb+rclone+.
- (lyra) sync Google Drive using \verb+rclone+.
- (lyra) verify that the latest copy of \verb+walden.pond+ is there
in the combox directory; it should contain 'Peaceful too.' in the
last line.
- (lyra) append ``I've a dream'' to \verb+walden.pond+.
- (lyra) sync Google Drive using \verb+rclone+.
- (grus) sync Google Drive using \verb+rclone+.
- (grus) verify that the latest copy of \verb+walden.pond+ is there
in the combox directory; it should contain ``I've a dream'' in the
last line.
- (grus) remove \verb+walden.pond+ from combox directory.
- (grus) sync Google Drive using \verb+rclone+.
- (lyra) sync Google Drive using \verb+rclone+.
- (lyra) verify that \verb+walden.pond+ is removed from the combox
directory.
- (grus) open dropbox and Google drive accounts from the web browser.
- (lyra) create file \verb+manufacturing.consent.+ with content ``Chomsky stuff?''.
- (lyra) sync Google Drive using \verb+rclone+.
- (grus) sync Google Drive using \verb+rclone+.
- (grus) verify that \verb+manufacturing.consent+ was created in the
combox directory.
- (grus) verify that the shards of \verb+manufacturing.consent+ were
created on Dropbox and Google Drive through the web browser.
\subsection{Testing on a GNU/Linux and an OS X machine}
combox was run on a GNU/Linux machine and an OS X machine and a file
was alternatively created/modified/renamed/deleted on one of the
machine and it was verified if the respective file was also
created/modified/renamed/deleted on the other machine. The GNU/Linux
machine was a virtual machine (\verb+lyra+) running Debian GNU/Linux
stable; the OS X machine was on Mavericks (10.9) during the initial
stage of testing, later it was upgraded to Yosemite (10.10). The node
directories to scatter files' shards were the Dropbox directory and
the Google Drive directory. The official Dropbox client was used to
automatically sync files from the Dropbox directory to the Dropbox'
server on both the GNU/Linux machine and the OS X machine; the
official Google Drive client was used to automatically sync files from
the Google Drive directory to Google Drive' server on OS X and
\verb+rclone+\cite{program:rclone} was used to sync files from the
Google Drive directory to Google Drive's server on GNU/Linux.
\subsubsection{Issues found}
\begin{itemize}
\item When a file was modified on another computer, on this computer
combox assumed that first shard (shard0) will be updated first and
also counted on the existence of the first shard (shard0). It was
observed that the order in which the shards were updated were
unpredictable on this computer and if the first shard (shard0) was
stored in the Dropbox directory, it will momentarily disappear
before the most updated shard becomes available in the Dropbox
directory; this broke combox. This issue was fixed on
2015-08-25\cite{git:bug-four-fix}. This issue is not got to do with
the nature of the setup but it is related to the Dropbox's behavior
elaborated in section \ref{ch-5-2gnus-issues}.
\item The official Google Drive client when it pulls an updated
version of the file from Google Drive' server, instead directly
updating the respective file on the computer, it deletes the older
version of the file and creates the latest version of the file at
the respective location in the Google Drive directory; this behavior
of the Google Drive confused and broke combox. This issue was fixed
2015-09-06 by making combox under the official Google Client's
behavior\cite{git:bug-googledc-fix}.
\item When a non-empty directory was move/renamed on another computer,
the old directory was not getting properly deleted on this computer;
this was happening because the files under the directory being
renamed were not deleted when it was time for \verb+NodeDirMonitor+
to \verb+rmdir+ the old directory. This issue again is not specific
to the nature of the setup but was found while testing combox on
this setup. This issue was fixed on
2015-09-12\cite{git:bug-six-fix}.
\item It was found that \verb+combox.file.rm_path+ function failed
when it was given a non-existent path to remove; this issue was
fixed on 2015-09-12\cite{git:bug-seven-fix}.
\end{itemize}
\subsubsection{Demo}
Demo of combox being used on a GNU/Linux machine and OS X machine can
be viewed at \url{https://ricketyspace.net/combox/combox-gnu-osx.webm}
\verb+lyra+ is the GNU/Linux (virtual) machine and
\verb+dhcp-129-1-66-1+ is the OS X machine that is being used for the
demo. The OS X machine is accessed through VNC\cite{article:vnc}.
Description of what happens in the demo follows:
- (\verb+lyra+) create file \verb+cat.stevens+ with content ``peace train''.
- (\verb+lyra+) sync Google Drive using \verb+rclone+.
- (\verb+dhcp-129-1-66-1+) verify that file \verb+cat.stevens+ is
created with content ``peace train''.
- (\verb+dhcp-129-1-66-1+) append string ``moonshadow'' to file
\verb+cat.stevens+.
- (\verb+lyra+) sync Google Drive using \verb+rclone+.
- (\verb+lyra+) verify that the file \verb+cat.stevens+ was updated
(modified); last line must have the string ``moonshadow''.
- (\verb+lyra+) append string ``father and son'' to the file
\verb+cat.stevens+.
- (\verb+lyra+) sync Google Drive using \verb+rclone+.
- (\verb+dhcp-129-1-66-1+) verify that the file \verb+cat.stevens+
was updated (modified); last line must have the string ``father and
son''.
- (\verb+dhcp-129-1-66-1+) rename file \verb+cat.stevens+ to
\verb+yusuf.islam+
- (\verb+lyra+) sync Google Drive using \verb+rclone+.
- (\verb+lyra+) verify that the file \verb+cat.stevens+ was renamed
to \verb+yusuf.islam+.
\subsection{Testing with a USB stick as a node}
combox was run on a GNU/Linux machine and an OS X machine and a file
was alternatively created/modified/deleted on one of the machine and
it was verified if the repsective file was also
create/modified/deleted on the other machine. The GNU/Linux machine
was a physical machine (\verb+grus+) running Debian GNU/Linux stable;
The OS X machine was on Mavericks (10.9). The node directories to
scatter files' shards were the Dropbox directory, Google Drive
directory and the USB stick (\verb+ZAPHOD+, FAT filesystem). The
official Dropbox client was used to automatically sync files from
Dropbox directory to Dropbox' server on both the GNU/Linux machine and
OS X machine; the official Google Drive client was used to
automatically sync files from the Google Drive directory to Google
Drive' server on OS X and \verb+rclone+\cite{program:rclone} was used
to sync files from the Google Drive directory to Google Drive's server
on GNU/Linux; the same USB stick (\verb+ZAPHOD+) was used on bothe
GNU/Linux and Dropbox to store the third shard (shard2) of a file.
\subsubsection{Caveats}
\begin{itemize}
\item When a removable USB disk is used as a node, combox must be
turned off before ejecting/unmounting the USB disk; combox does not
expect a node directory to disappear when it is running, if the USB
disk is removed when combox is running, then combox goes to a
undefined state.
\item When a file modified on machine A is synced to machine B, combox
must be turned on first before turning on Dropbox and Google Drive
clients and the shard in the USB disk needs to be ``touched'' for
combox to detect that the file was modified on the remote computer
and update the file locally on this machine.
\item File rename/move does not work. To make it work, core
functionality of combox must be re-written.
\end{itemize}
\subsubsection{Demo}
\section{Stress testing}
\begin{figure}[h]
\centering
\input{graphs/tot-time.tex}
\caption{time to process all files}
\end{figure}
\begin{figure}[h]
\centering
\input{graphs/avg-time-sae.tex}
\caption{avg. time to split and encrypt}
\end{figure}
\begin{figure}[h]
\centering
\input{graphs/tot-time-diff.tex}
\caption{time to process all files - difference between 2015 and 2016}
\end{figure}
\begin{figure}[h]
\centering
\input{graphs/avg-time-sae-diff.tex}
\caption{avg. time to split and encrypt - difference between 2015 and 2016}
\end{figure}
|