<commit_before>package maas

import (
	"bytes"
	"encoding/base64"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/gomaasapi"
	"launchpad.net/juju-core/environs"
	"math/rand"
	"net/http"
	"net/url"
	"sync"
)

type StorageSuite struct {
	ProviderSuite
}

var _ = Suite(new(StorageSuite))

// makeStorage creates a MAAS storage object for the running test.
func (s *StorageSuite) makeStorage(name string) *maasStorage {
	maasobj := s.testMAASObject.MAASObject
	env := maasEnviron{name: name, maasClientUnlocked: &maasobj}
	return NewStorage(&env).(*maasStorage)
}

// makeRandomBytes returns an array of arbitrary byte values.
func makeRandomBytes(length int) []byte {
	data := make([]byte, length)
	for index := range data {
		data[index] = byte(rand.Intn(256))
	}
	return data
}

// fakeStoredFile creates a file directly in the (simulated) MAAS file store.
// It will contain an arbitrary amount of random data.  The contents are also
// returned.
//
// If you want properly random data here, initialize the randomizer first.
// Or don't, if you want consistent (and debuggable) results.
func (s *StorageSuite) fakeStoredFile(storage environs.Storage, name string) gomaasapi.MAASObject {
	data := makeRandomBytes(rand.Intn(10))
	return s.testMAASObject.TestServer.NewFile(name, data)
}

func (s *StorageSuite) TestGetSnapshotCreatesClone(c *C) {
	original := s.makeStorage("storage-name")
	snapshot := original.getSnapshot()
	c.Check(snapshot.environUnlocked, Equals, original.environUnlocked)
	c.Check(snapshot.maasClientUnlocked.URL().String(), Equals, original.maasClientUnlocked.URL().String())
	// Snapshotting locks the original internally, but does not leave
	// either the original or the snapshot locked.
	c.Check(original.Mutex, Equals, sync.Mutex{})
	c.Check(snapshot.Mutex, Equals, sync.Mutex{})
}

func (s *StorageSuite) TestGetRetrievesFile(c *C) {
	const filename = "stored-data"
	storage := s.makeStorage("get-retrieves-file")
	file := s.fakeStoredFile(storage, filename)
	base64Content, err := file.GetField("content")
	c.Assert(err, IsNil)
	content, err := base64.StdEncoding.DecodeString(base64Content)
	c.Assert(err, IsNil)

	reader, err := storage.Get(filename)
	c.Assert(err, IsNil)
	defer reader.Close()

	buf, err := ioutil.ReadAll(reader)
	c.Assert(err, IsNil)
	c.Check(len(buf), Equals, len(content))
	c.Check(buf, DeepEquals, content)
}

func (s *StorageSuite) TestRetrieveFileObjectReturnsFileObject(c *C) {
	const filename = "myfile"
	stor := s.makeStorage("rfo-test")
	file := s.fakeStoredFile(stor, filename)
	fileURI, err := file.GetField("anon_resource_uri")
	c.Assert(err, IsNil)
	fileContent, err := file.GetField("content")
	c.Assert(err, IsNil)

	obj, err := stor.retrieveFileObject(filename)
	c.Assert(err, IsNil)

	uri, err := obj.GetField("anon_resource_uri")
	c.Assert(err, IsNil)
	c.Check(uri, Equals, fileURI)
	content, err := obj.GetField("content")
	c.Check(content, Equals, fileContent)
}

func (s *StorageSuite) TestRetrieveFileObjectReturnsNotFound(c *C) {
	stor := s.makeStorage("rfo-test")
	_, err := stor.retrieveFileObject("nonexistent-file")
	c.Assert(err, NotNil)
	c.Check(err, FitsTypeOf, environs.NotFoundError{})
}

func (s *StorageSuite) TestRetrieveFileObjectEscapesName(c *C) {
	const filename = "#a?b c&d%e!"
	data := []byte("File contents here")
	stor := s.makeStorage("rfo-test")
	err := stor.Put(filename, bytes.NewReader(data), int64(len(data)))
	c.Assert(err, IsNil)

	obj, err := stor.retrieveFileObject(filename)
	c.Assert(err, IsNil)

	content, err := obj.GetField("content")
	c.Check(content, Equals, data)
}

func (s *StorageSuite) TestFileContentsAreBinary(c *C) {
	const filename = "myfile.bin"
	data := []byte{0, 1, 255, 2, 254, 3}
	stor := s.makeStorage("binary-test")

	err := stor.Put(filename, bytes.NewReader(data), int64(len(data)))<commit_msg>Fix up mistake in test: this version of file contents is base64-encoded.<commit_after>package maas

import (
	"bytes"
	"encoding/base64"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/gomaasapi"
	"launchpad.net/juju-core/environs"
	"math/rand"
	"net/http"
	"net/url"
	"sync"
)

type StorageSuite struct {
	ProviderSuite
}

var _ = Suite(new(StorageSuite))

// makeStorage creates a MAAS storage object for the running test.
func (s *StorageSuite) makeStorage(name string) *maasStorage {
	maasobj := s.testMAASObject.MAASObject
	env := maasEnviron{name: name, maasClientUnlocked: &maasobj}
	return NewStorage(&env).(*maasStorage)
}

// makeRandomBytes returns an array of arbitrary byte values.
func makeRandomBytes(length int) []byte {
	data := make([]byte, length)
	for index := range data {
		data[index] = byte(rand.Intn(256))
	}
	return data
}

// fakeStoredFile creates a file directly in the (simulated) MAAS file store.
// It will contain an arbitrary amount of random data.  The contents are also
// returned.
//
// If you want properly random data here, initialize the randomizer first.
// Or don't, if you want consistent (and debuggable) results.
func (s *StorageSuite) fakeStoredFile(storage environs.Storage, name string) gomaasapi.MAASObject {
	data := makeRandomBytes(rand.Intn(10))
	return s.testMAASObject.TestServer.NewFile(name, data)
}

func (s *StorageSuite) TestGetSnapshotCreatesClone(c *C) {
	original := s.makeStorage("storage-name")
	snapshot := original.getSnapshot()
	c.Check(snapshot.environUnlocked, Equals, original.environUnlocked)
	c.Check(snapshot.maasClientUnlocked.URL().String(), Equals, original.maasClientUnlocked.URL().String())
	// Snapshotting locks the original internally, but does not leave
	// either the original or the snapshot locked.
	c.Check(original.Mutex, Equals, sync.Mutex{})
	c.Check(snapshot.Mutex, Equals, sync.Mutex{})
}

func (s *StorageSuite) TestGetRetrievesFile(c *C) {
	const filename = "stored-data"
	storage := s.makeStorage("get-retrieves-file")
	file := s.fakeStoredFile(storage, filename)
	base64Content, err := file.GetField("content")
	c.Assert(err, IsNil)
	content, err := base64.StdEncoding.DecodeString(base64Content)
	c.Assert(err, IsNil)

	reader, err := storage.Get(filename)
	c.Assert(err, IsNil)
	defer reader.Close()

	buf, err := ioutil.ReadAll(reader)
	c.Assert(err, IsNil)
	c.Check(len(buf), Equals, len(content))
	c.Check(buf, DeepEquals, content)
}

func (s *StorageSuite) TestRetrieveFileObjectReturnsFileObject(c *C) {
	const filename = "myfile"
	stor := s.makeStorage("rfo-test")
	file := s.fakeStoredFile(stor, filename)
	fileURI, err := file.GetField("anon_resource_uri")
	c.Assert(err, IsNil)
	fileContent, err := file.GetField("content")
	c.Assert(err, IsNil)

	obj, err := stor.retrieveFileObject(filename)
	c.Assert(err, IsNil)

	uri, err := obj.GetField("anon_resource_uri")
	c.Assert(err, IsNil)
	c.Check(uri, Equals, fileURI)
	content, err := obj.GetField("content")
	c.Check(content, Equals, fileContent)
}

func (s *StorageSuite) TestRetrieveFileObjectReturnsNotFound(c *C) {
	stor := s.makeStorage("rfo-test")
	_, err := stor.retrieveFileObject("nonexistent-file")
	c.Assert(err, NotNil)
	c.Check(err, FitsTypeOf, environs.NotFoundError{})
}

func (s *StorageSuite) TestRetrieveFileObjectEscapesName(c *C) {
	const filename = "#a?b c&d%e!"
	data := []byte("File contents here")
	stor := s.makeStorage("rfo-test")
	err := stor.Put(filename, bytes.NewReader(data), int64(len(data)))
	c.Assert(err, IsNil)

	obj, err := stor.retrieveFileObject(filename)
	c.Assert(err, IsNil)

	base64Content, err := obj.GetField("content")
	c.Assert(err, IsNil)
	content, err := base64.StdEncoding.DecodeString(base64Content)
	c.Assert(err, IsNil)
	c.Check(content, DeepEquals, data)
}

func (s *StorageSuite) TestFileContentsAreBinary(c *C) {
	const filename = "myfile.bin"
	data := []byte{0, 1, 255, 2, 254, 3}
	stor := s.makeStorage("binary-test")

	err := stor.Put(filename, bytes.NewReader(data), int64(len(data)))
{'fraction_non_alphanumeric': 0.14309399311312332, 'fraction_numerical': 0.007907154699655656, 'mean_word_length': 5.370430544272949, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4527439', 'n_tokens_mistral': 2829, 'n_tokens_neox': 2774, 'n_words': 641}