Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: StorjOld/RandomIO
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.2.1
Choose a base ref
...
head repository: StorjOld/RandomIO
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
  • 11 commits
  • 6 files changed
  • 2 contributors

Commits on May 15, 2015

  1. PEP8 Fixes

    super3 committed May 15, 2015
    Copy the full SHA
    8b806b6 View commit details

Commits on May 21, 2015

  1. Windows Unit Test Hack

    super3 committed May 21, 2015
    Copy the full SHA
    3d780ba View commit details
  2. Changed Build Notifications

    super3 committed May 21, 2015
    Copy the full SHA
    38a996c View commit details
  3. Copy the full SHA
    2207589 View commit details
  4. Removed a Testing Statement

    super3 committed May 21, 2015
    Copy the full SHA
    bdd7218 View commit details
  5. Fixing PEP8 Violation

    super3 committed May 21, 2015
    Copy the full SHA
    a1e82fd View commit details
  6. Fix Badge

    super3 committed May 21, 2015
    Copy the full SHA
    1cda08b View commit details

Commits on Aug 13, 2015

  1. Cleaning up unit tests

    Fixing a few issues in the unit tests:
      Removing redis, iotools tests, which had external dependencies
      Cleaning up imports
      Rewriting dump() test to use io.BytesIO instead of writing to the actual
      filesystem
    mtlynch committed Aug 13, 2015
    Copy the full SHA
    ddc019b View commit details

Commits on Aug 17, 2015

  1. Copy the full SHA
    12ddf67 View commit details
  2. Merge pull request #9 from mtlynch/fix-unit-tests

    Cleaning up unit tests
    super3 committed Aug 17, 2015
    Copy the full SHA
    8f90d44 View commit details
  3. Add Badges

    super3 committed Aug 17, 2015
    Copy the full SHA
    600430e View commit details
Showing with 31 additions and 268 deletions.
  1. +1 −4 .travis.yml
  2. +4 −71 README.md
  3. +15 −15 RandomIO/RandomIO.py
  4. +0 −105 bin/IOTools.py
  5. +1 −3 setup.py
  6. +10 −70 tests/test_unit.py
5 changes: 1 addition & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -3,8 +3,6 @@ python:
- 2.7
- 3.3
- 3.4
services:
- redis-server
install:
- pip install coverage coveralls .
after_success:
@@ -13,5 +11,4 @@ script:
- coverage run setup.py test -a "--doctest-modules --pep8 -v tests/ RandomIO/"
- coverage report -m --include=RandomIO/*,bin/*
notifications:
slack:
secure: UfAeGUD0YUBwb3IS6aSGm+pSdkcrY3Wqqfru4e0E0ZdXs9hMyaQcw8hI7mQqPey1pOWCWw4i3npAb21p8JfPqvV+gMgbsIksla15kBPiej6d2zLwNplg3ewAn7SEY+pO2ItyGKc05uMELOgz83ntgPVW+vE1OeY34Eg7l5cmThM=
slack: storjcommunity:G9Q7PFrK7LQGTuomtP8h5oOH
75 changes: 4 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
RandomIO
===============

[![Build Status](https://travis-ci.org/Storj/RandomIO.svg)](https://travis-ci.org/Storj/RandomIO) [![Coverage Status](https://img.shields.io/coveralls/Storj/RandomIO.svg)](https://coveralls.io/r/Storj/RandomIO?branch=master)
[![Build Status](https://travis-ci.org/Storj/RandomIO.svg)](https://travis-ci.org/Storj/RandomIO)
[![Coverage Status](https://img.shields.io/coveralls/Storj/RandomIO.svg)](https://coveralls.io/r/Storj/RandomIO?branch=master)
[![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/storj/RandomIO/master/LICENSE)
[![GitHub Issues](https://img.shields.io/github/issues/storj/randomio.svg)](https://github.com/storj/RandomIO/issues)

`RandomIO` provides a readable interface for cryptographic quality random bytes. It also allows for generation of random files, dumping random bytes to files, and a `.read()` method for reading bytes.

@@ -75,76 +78,6 @@ with open('path/to/file','rb') as f:
# b'\xec\xf4C\xeb\x1d\rU%\xca\xae'
```

### CLI Tools

RandomIO includes a small set of CLI tools in IOTools.py:

```
$python IOTools.py --help
usage: IOTools.py <command> [<args>]
Currently available commands include:
pairgen Outputs a series of seed-hash pairs for files generated using the RandomIO library.
A series of command-line tools that make use of the RandomIO library.
positional arguments:
command Command to run.
optional arguments:
-h, --help show this help message and exit
```

Currently, `pairgen` is the only available tool:

```
$ IOTools.py pairgen --help
usage: IOTools.py [-h] [-l LENGTH] [-p PAIRS] [-o OUTPUT] [-v] size
Output a series of seed-hash pairs for files generated in memory using the
RandomIO library.
positional arguments:
size The target size of each file generated and hashed (in
bytes).
optional arguments:
-h, --help show this help message and exit
-l LENGTH, --length LENGTH
The length of the random seed string to use.
-p PAIRS, --pairs PAIRS
The number of seed-hash pairs to generate.
-o OUTPUT, --output OUTPUT
The name of the file you wish to write pairs to.
-r, --redis Write to file using Redis protocol.
-v, --verbose Increase output verbosity.
This tool can be used to pre-generate seed-hash pairs for the Storj uptick
service.
```

Example output of `pairgens`:

```
$ IOTools.py pairgen 100000000 -p5 -l 10 -o mypairs.txt -v
Pair 0: Generating hash for 95.4MB file with seed 6a95c93fa9ca92d249d2...
done!
Pair 1: Generating hash for 95.4MB file with seed 7b31909908ff413061ce...
done!
Pair 2: Generating hash for 95.4MB file with seed a440bcd97af94701282c...
done!
Pair 3: Generating hash for 95.4MB file with seed 0f1f9dad1d6da7e03367...
done!
Pair 4: Generating hash for 95.4MB file with seed f146dbbe9c1706e1c3d6...
done!
```

Note that files are generated and hashed in memory. In addition, seeds displayed and/or written to file are hex-encoded. Actual seeds must be decoded before generating hash.

When writing pairs to file using Redis's mass insertion format, you can use the following command to import your pairs to Redis:

`cat pairs.out | redis-cli --pipe`

### Performance

```
30 changes: 15 additions & 15 deletions RandomIO/RandomIO.py
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ def __init__(self, seed=None, size=None):
self.blocksize = 16
self.ctrblocksize = self.blocksize // 2
self.ctr = Counter.new(self.blocksize * 8)
if (seed is None):
if seed is None:
seed = os.urandom(32)
try:
self.key = SHA256.new(seed).digest()
@@ -76,7 +76,7 @@ def _read_buffer(self, size):
so may return less than size bytes
"""
remaining = len(self.buffer) - self.bufpos
if (size < remaining):
if size < remaining:
# we can read directly from the buffer
ret = self.buffer[self.bufpos:self.bufpos + size]
self.bufpos += len(ret)
@@ -92,10 +92,10 @@ def seek(self, offset, whence=os.SEEK_SET):
"""Seeks to the offset specified. Offsets must be specified absolutely
from the beginning of the stream
"""
if (whence == os.SEEK_CUR):
if whence == os.SEEK_CUR:
offset += self.offset
elif (whence == os.SEEK_END):
if (self.size is None):
elif whence == os.SEEK_END:
if self.size is None:
raise RuntimeError('Cannot seek from end of stream if size'
' is unknown.')
offset = self.size - offset
@@ -112,7 +112,7 @@ def seek(self, offset, whence=os.SEEK_SET):
self.aes = AES.new(self.key, AES.MODE_CTR, counter=self.ctr)

rem = offset % self.blocksize
if (rem > 0):
if rem > 0:
self._fill_buffer()
self._seek_buffer(rem)

@@ -124,11 +124,11 @@ def tell(self):
return self.offset

def _interpret_size(self, size):
if (self.size is not None):
if (size is None or self.offset + size > self.size):
if self.size is not None:
if size is None or self.offset + size > self.size:
size = self.size - self.offset
else:
if (size is None):
if size is None:
# we don't know how much to return
raise RuntimeError('Stream size must be specified if bytes'
' to read is not.')
@@ -143,7 +143,7 @@ def read(self, size=None):
"""
size = self._interpret_size(size)

if (size < 1):
if size < 1:
return b''

# if we are reading less than 8 bytes, this function will buffer so
@@ -162,10 +162,10 @@ def read(self, size=None):
# read some raw bytes
rem = size % self.blocksize
raw_size = size - rem
if (raw_size > 0):
if raw_size > 0:
ret += self._read_raw(raw_size)

if (rem > 0):
if rem > 0:
self._fill_buffer()
ret += self._read_buffer(rem)

@@ -181,8 +181,8 @@ def dump(self, fp, size=None):
size = self._interpret_size(size)

bufsz = self.bufsz
while (size > 0):
if (size < bufsz):
while size > 0:
if size < bufsz:
bufsz = size
fp.write(self.read(bufsz))
size -= bufsz
@@ -204,7 +204,7 @@ def genfile(self, size=None, path=''):
:param path: the file path, or directory
:returns: the file path
"""
if (os.path.isdir(path) or len(path) == 0):
if os.path.isdir(path) or len(path) == 0:
path = os.path.join(path, hexlify(os.urandom(16)).decode('utf-8'))

with open(path, 'wb') as f:
105 changes: 0 additions & 105 deletions bin/IOTools.py

This file was deleted.

4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
@@ -32,11 +32,10 @@
LONG_DESCRIPTION = open('README.md').read()

install_requirements = [
'pycrypto >= 2.6.1'
'pycrypto >= 2.6.1',
]

test_requirements = [
'redis>=2.10.3',
'pytest>=2.6.4',
'pytest-pep8',
'pytest-cache',
@@ -79,5 +78,4 @@ def run_tests(self):
install_requires=install_requirements,
tests_require=test_requirements,
keywords=['storj', 'randomIO', 'random generator'],
scripts=['bin/IOTools.py'],
)
80 changes: 10 additions & 70 deletions tests/test_unit.py
Original file line number Diff line number Diff line change
@@ -23,32 +23,15 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import io
import os
import redis
import hashlib
import subprocess
import binascii
import unittest

import RandomIO
from sys import platform as _platform

if _platform.startswith('linux') or _platform == 'darwin':
cat_cmd = 'cat'
iotools_call = ['IOTools.py']
elif _platform == 'win32':
cat_cmd = 'type'
iotools_call = ['python', os.path.join('bin', 'IOTools.py')]


class TestRandomIO(unittest.TestCase):

def setUp(self):
pass

def tearDown(self):
pass

def test_gen(self):
s = RandomIO.RandomIO()
b = s.read(100)
@@ -103,26 +86,17 @@ def test_dump(self):
s1 = RandomIO.RandomIO('seed string')
s2 = RandomIO.RandomIO('seed string')

file1 = 'file1'
file2 = 'file2'
DUMP_LENGTH = 100

with open(file1, 'wb') as f:
s1.dump(f, 100)
file1 = io.BytesIO()
file2 = io.BytesIO()

with open(file2, 'wb') as f:
s2.dump(f, 100)
s1.dump(file1, DUMP_LENGTH)
s2.dump(file2, DUMP_LENGTH)

with open(file1, 'rb') as f:
contents1 = f.read()

with open(file2, 'rb') as f:
contents2 = f.read()

self.assertEqual(len(contents1), 100)
self.assertEqual(contents1, contents2)

os.remove(file1)
os.remove(file2)
self.assertEqual(file1.tell(), DUMP_LENGTH)
self.assertEqual(file2.tell(), DUMP_LENGTH)
self.assertEqual(file1.getvalue(), file2.getvalue())

def test_genfile(self):
path = RandomIO.RandomIO('seed string').genfile(100)
@@ -258,40 +232,6 @@ def test_seek_end_not_possible(self):
str(ex.exception),
'Cannot seek from end of stream if size is unknown.')

def test_iotools_txt(self):
output = 'txt_test.out'
size = 10485760
subprocess.call(
iotools_call + ['pairgen', str(size),
'-p', '10', '-o', output])

with open(output, 'r') as pairsfile:
for line in pairsfile:
(hexseed, hash) = line.rstrip().split(' ')
seed = binascii.unhexlify(hexseed)
testhash = hashlib.sha256(
RandomIO.RandomIO(seed).read(size)).hexdigest()
self.assertEqual(hash, testhash)
os.remove(output)

def test_iotools_redis(self):
r = redis.StrictRedis(host='localhost', port=6379, db=0)
output = 'redis_test.out'
size = 10485760

subprocess.call(
iotools_call + ['pairgen', str(size), '-p', '10', '-o', output,
'--redis'])
subprocess.call(
'{0} {1} | redis-cli --pipe'.format(cat_cmd, output), shell=True)

for hexseed in r.scan_iter():
seed = binascii.unhexlify(hexseed)
testhash = hashlib.sha256(
RandomIO.RandomIO(seed).read(size)).hexdigest()
self.assertEqual(r.get(hexseed).decode('ascii'), testhash)
os.remove(output)
r.flushall()

if __name__ == '__main__':
unittest.main()