Merge lp:~zyga/checkbox/attachment-fixes into lp:checkbox

Proposed by Zygmunt Krynicki
Status: Merged
Approved by: Sylvain Pineau
Approved revision: 3502
Merged at revision: 3500
Proposed branch: lp:~zyga/checkbox/attachment-fixes
Merge into: lp:checkbox
Diff against target: 121 lines (+73/-3)
3 files modified
plainbox/plainbox/impl/providers/stubbox/manage.py (+2/-1)
plainbox/plainbox/impl/providers/stubbox/units/jobs/stub.pxu (+59/-0)
plainbox/plainbox/vendor/extcmd/glibc.py (+12/-2)
To merge this branch: bzr merge lp:~zyga/checkbox/attachment-fixes
Reviewer Review Type Date Requested Status
Daniel Manrique (community) Needs Information
Sylvain Pineau (community) Approve
Review via email: mp+244596@code.launchpad.net

Description of the change

284c6e6 plainbox:providers:stubbox: disable strict validation
82ac810 plainbox:providers:stubbox: add test attachment jobs
46b8e41 plainbox:excmd: don't expose non-blocking pipes to children

To post a comment you must log in.
lp:~zyga/checkbox/attachment-fixes updated
3501. By Zygmunt Krynicki

plainbox:providers:stubbox: add test attachment jobs

This patch adds a collection of stubbox jobs for testing attachments.

    stub/text-attachment: prints (and captures) a small UTF-8 encoded
    piece of text. It can catch errors in handling output encoding

    stub/large-text-attachment: prints (and captures) a large UTF-8
    encoded piece of text. It can catch errors related to buffering.

    stub/binary-attachment: prints (and captures) a
    specifically-difficult-to-handle binary data consisting of all 256
    bytes

    stub/large-binary-attachment: prints (and captures) a large binary
    blob to test handling of memory efficiency.

Signed-off-by: Zygmunt Krynicki <email address hidden>

3502. By Zygmunt Krynicki

plainbox:excmd: don't expose non-blocking pipes to children

This patch fixes a bug in the glibc-based extcmd implementation.

The communication pipes that are created to pass stdout and stderr data
were created in non-blocking mode and that non-blocking pipe was exposed
to the child process. A child process writing fast enough could fill the
pipe and get EAGAIN. Since applications are not generally designed to
handle that it would cause random failures.

The fix based on creating normal (blocking) pipes and only set the
non-blocking mode in the parent process that has an event loop.

Fixes: https://bugs.launchpad.net/plainbox/+bug/1401886

Signed-off-by: Zygmunt Krynicki <email address hidden>

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

+1, thanks for the quick fix

review: Approve
Revision history for this message
Daniel Manrique (roadmr) wrote :

+1 on the fix, I have a couple of minor questions but I'd be OK with the test definitions as well.

review: Needs Information
Revision history for this message
Zygmunt Krynicki (zyga) wrote :

I've selected Polish out of selfishnesss, it's equally good as any other non-ASCII sequence.

I've used /dev/zero instead of a hardcoded gzipped file full of zeros (it's just silly to have that file in the tree in retrospective). The purpose of the test is to see how we handle *large* files, not if we can handle them at all (there, an existing, more comprehensive test checks *each* possible byte)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'plainbox/plainbox/impl/providers/stubbox/data'
2=== added file 'plainbox/plainbox/impl/providers/stubbox/data/all-bytes'
3Binary files plainbox/plainbox/impl/providers/stubbox/data/all-bytes 1970-01-01 00:00:00 +0000 and plainbox/plainbox/impl/providers/stubbox/data/all-bytes 2014-12-12 14:51:09 +0000 differ
4=== modified file 'plainbox/plainbox/impl/providers/stubbox/manage.py'
5--- plainbox/plainbox/impl/providers/stubbox/manage.py 2014-04-04 09:41:22 +0000
6+++ plainbox/plainbox/impl/providers/stubbox/manage.py 2014-12-12 14:51:09 +0000
7@@ -75,5 +75,6 @@
8 name=stubbox_def.name,
9 version=stubbox_def.version,
10 description=stubbox_def.description,
11- gettext_domain=stubbox_def.gettext_domain
12+ gettext_domain=stubbox_def.gettext_domain,
13+ strict=False,
14 )
15
16=== modified file 'plainbox/plainbox/impl/providers/stubbox/units/jobs/stub.pxu'
17--- plainbox/plainbox/impl/providers/stubbox/units/jobs/stub.pxu 2014-11-25 11:33:53 +0000
18+++ plainbox/plainbox/impl/providers/stubbox/units/jobs/stub.pxu 2014-12-12 14:51:09 +0000
19@@ -352,3 +352,62 @@
20 command: test $(id -u) -eq 0
21 estimated_duration: 0.1
22 category_id: superuser
23+
24+id: stub/text-attachment
25+_summary: A job that attaches a plain text file
26+_description:
27+ This job attaches a simple, fixed, piece of UTF-8 encoded text as attachment
28+plugin: attachment
29+flags: preserve-locale
30+# The subsequent polish text is a typical 'the quick brown fox...' text that
31+# is used just because it's likely to expose any non-ASCII text handling bugs.
32+command:
33+ echo "zazółć gęślą jaźń"
34+estimated_duration: 0.1
35+category_id: plugin-representative
36+
37+id: stub/binary-attachment
38+_summary: A job that attaches representative binary data
39+_description:
40+ This job generates bytes 0 through 255 to test handling of bytes that may
41+ occur but be mishandled by our I/O processing engine.
42+plugin: attachment
43+flags: preserve-locale
44+# The all-bytes file can be generated with the following piece of bash but
45+# I wanted to avoid reliance on the obscure escape processing for
46+# portability:
47+# for i in $(seq 0 255); do
48+# echo -n -e "\x$(printf %x $i)"
49+# done
50+command:
51+ cat $PLAINBOX_PROVIDER_DATA/all-bytes
52+
53+id: stub/large-text-attachment
54+_summary: A job that attaches a plain text file
55+_description:
56+ This job attaches a large, repeated sequence of UTF-8 encoded text as
57+ attachment. It helps to stress the I/O handling code that might not happen in
58+ a trivial (short / small) attachment.
59+plugin: attachment
60+flags: preserve-locale
61+# The subsequent polish text is a typical 'the quick brown fox...' text that
62+# is used just because it's likely to expose any non-ASCII text handling bugs.
63+command:
64+ for i in $(seq 100000); do
65+ echo "$i: zazółć gęślą jaźń"
66+ done
67+estimated_duration: 0.1
68+category_id: stress
69+
70+id: stub/large-binary-attachment
71+_summary: A job that attaches representative binary data
72+_description:
73+ This job attaches 16GBs of zeros to see if we can handle (mostly on the memory
74+ front) such types of attachments, e.g. someone attaching a swap file, or
75+ something equally unexpected and very large.
76+plugin: attachment
77+flags: preserve-locale
78+command:
79+ dd if=/dev/zero bs=1M count=16384
80+estimated_duration: 750
81+category_id: stress
82
83=== modified file 'plainbox/plainbox/vendor/extcmd/glibc.py'
84--- plainbox/plainbox/vendor/extcmd/glibc.py 2014-12-05 12:07:05 +0000
85+++ plainbox/plainbox/vendor/extcmd/glibc.py 2014-12-12 14:51:09 +0000
86@@ -24,6 +24,7 @@
87 """
88 import contextlib
89 import errno
90+import fcntl
91 import logging
92 import os
93 import signal
94@@ -110,9 +111,9 @@
95 _logger.debug("Obtained: %r", sfd)
96 sigmask = pthread_sigmask(signal_list)
97 _logger.debug("Obtained: %r", sigmask)
98- stdout_pair = pipe2(O_CLOEXEC | O_NONBLOCK)
99+ stdout_pair = pipe2(O_CLOEXEC)
100 _logger.debug("Obtained: %r", stdout_pair)
101- stderr_pair = pipe2(O_CLOEXEC | O_NONBLOCK)
102+ stderr_pair = pipe2(O_CLOEXEC)
103 _logger.debug("Obtained: %r", stderr_pair)
104 key = selector.register(stdout_pair[0], EVENT_READ, 'stdout')
105 _logger.debug("Registered key with selector: %r", key)
106@@ -171,6 +172,15 @@
107 os.exit(-1)
108 else:
109 _logger.debug("Forked child process: %r", pid)
110+ # Make all pipes non-blocking as the loop below cannot work
111+ # with any blocking I/O.
112+ flags = fcntl.fcntl(stdout_pair[0], fcntl.F_GETFL)
113+ flags |= O_NONBLOCK
114+ fcntl.fcntl(stdout_pair[0], fcntl.F_SETFL, flags)
115+ flags = fcntl.fcntl(stderr_pair[0], fcntl.F_GETFL)
116+ flags |= O_NONBLOCK
117+ fcntl.fcntl(stderr_pair[0], fcntl.F_SETFL, O_NONBLOCK)
118+ # Close the write sides of the pipes
119 os.close(stdout_pair[1])
120 os.close(stderr_pair[1])
121 return self._loop(selector, pid)

Subscribers

People subscribed via source and target branches