From 49005bf259d1502ecc1d5461aa2a39bae3f31ecf Mon Sep 17 00:00:00 2001 From: Tristan Claverie Date: Thu, 28 Jan 2016 01:31:23 +0100 Subject: [PATCH] [dfssp] Add mongo entities for mongo and tests --- .gitlab-ci.yml | 4 + dfssp/contract/entity.go | 71 ++++++++++++++++ dfssp/contract/entity_test.go | 122 +++++++++++++++++++++++++++ dfssp/user/entity.go | 65 +++++++++++++++ dfssp/user/entity_test.go | 151 ++++++++++++++++++++++++++++++++++ 5 files changed, 413 insertions(+) create mode 100644 dfssp/contract/entity.go create mode 100644 dfssp/contract/entity_test.go create mode 100644 dfssp/user/entity.go create mode 100644 dfssp/user/entity_test.go diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1d3f647..e1085f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,6 +24,8 @@ Unit tests: - "go test -coverprofile mails.part -v dfss/mails" - "go test -coverprofile net.part -v dfss/net" - "go test -coverprofile authority.part -v dfss/dfssp/authority" + - "go test -coverprofile dfssp_user.part -v dfss/dfssp/user" + - "go test -coverprofile dfssp_contract.part -v dfss/dfssp/contract" - "echo 'mode: set' *part > c.out" - "grep -h -v 'mode: set' *part >> c.out" - "go tool cover -html=c.out -o coverage.html" @@ -39,6 +41,8 @@ ARM tests: - "go test -cover -short -v dfss/mgdb" - "go test -cover -short -v dfss/net" - "go test -cover -short -v dfss/dfssp/authority" + - "go test -cover -short -v dfss/dfssp/user" + - "go test -cover -short -v dfss/dfssp/contract" Code lint: stage: test diff --git a/dfssp/contract/entity.go b/dfssp/contract/entity.go new file mode 100644 index 0000000..43ca952 --- /dev/null +++ b/dfssp/contract/entity.go @@ -0,0 +1,71 @@ +package contract + +import ( + "dfss/mgdb" + "time" + + "gopkg.in/mgo.v2/bson" +) + +// File : Represents a file structure +type File struct { + Name string `key:"name" bson:"name"` // Name of the File + Hash string `key:"hash" bson:"hash"` // Hash of the File + Hosted bool `key:"hosted" bson:"hosted"` // True if hosted on the platform, else false +} + +// Signer : Informations about the signer of a contract +type Signer struct { + UserID bson.ObjectId `key:"userId" bson:"userId"` + Email string `key:"email" bson:"email"` + Hash string `key:"hash" bson:"hash"` +} + +// NewSigner : Creates a signer associated to a contract +func NewSigner() *Signer { + return &Signer{ + UserID: bson.NewObjectId(), + } +} + +// Contract : Informations about a contract to be signed +type Contract struct { + ID bson.ObjectId `key:"_id" bson:"_id"` + Date time.Time `key:"date" bson:"date"` + Comment string `key:"comment" bson:"comment"` + Ready bool `key:"ready" bson:"ready"` + File *File `key:"file" bson:"file"` + Signers []Signer `key:"signers" bson:"signers"` +} + +// NewContract : Creates a new contract +func NewContract() *Contract { + file := File{} + var signers []Signer + return &Contract{ + ID: bson.NewObjectId(), + Date: time.Now(), + File: &file, + Signers: signers, + } +} + +// AddSigner : Add a signer to the contract +func (c *Contract) AddSigner(email, hash string) { + signer := NewSigner() + signer.Email = email + signer.Hash = hash + c.Signers = append(c.Signers, *signer) +} + +// Repository to contains every complex methods related to contract +type Repository struct { + Collection *mgdb.MongoCollection +} + +// NewRepository : Creates a new Contract Repository +func NewRepository(collection *mgdb.MongoCollection) *Repository { + return &Repository{ + collection, + } +} diff --git a/dfssp/contract/entity_test.go b/dfssp/contract/entity_test.go new file mode 100644 index 0000000..bf0f6d2 --- /dev/null +++ b/dfssp/contract/entity_test.go @@ -0,0 +1,122 @@ +package contract + +import ( + "dfss/mgdb" + "fmt" + "os" + "testing" +) + +var err error +var collection *mgdb.MongoCollection +var manager *mgdb.MongoManager +var dbURI string + +var repository *Repository + +func TestMain(m *testing.M) { + + dbURI = os.Getenv("DFSS_MONGO_URI") + if dbURI == "" { + dbURI = "mongodb://localhost/dfss" + } + + manager, err = mgdb.NewManager(dbURI) + collection = manager.Get("demo") + + repository = NewRepository(collection) + + // Run + code := m.Run() + + // Teardown + // The collection is created automatically on + // first connection, that's why we do not recreate it manually + err = collection.Drop() + + if err != nil { + fmt.Println("An error occurred while droping the collection") + } + manager.Close() + + os.Exit(code) +} + +func TestAddSigner(t *testing.T) { + contract := NewContract() + contract.AddSigner("mail1", "hash1") + contract.AddSigner("mail2", "hash2") + + signers := contract.Signers + var fixedSigners [2]Signer + copy(fixedSigners[:], signers[:2]) + + if len(signers) != 2 { + t.Fatal("Signers are not inserted correctly") + } + + helperCompareEmailAndHash(t, fixedSigners) +} + +func helperCompareFiles(t *testing.T, contract, fetched Contract) { + if contract.File.Name != fetched.File.Name || contract.File.Hash != fetched.File.Hash || contract.File.Hosted != fetched.File.Hosted { + t.Fatal("Contract files doesn't match") + } +} +func helperCompareEmailAndHash(t *testing.T, signers [2]Signer) { + if signers[0].Email != "mail1" && signers[0].Email != "mail2" || signers[1].Email != "mail1" && signers[1].Email != "mail2" { + t.Fatal("Signers are not correctly added") + } + if signers[0].Hash != "hash1" && signers[0].Hash != "hash2" || signers[1].Hash != "hash1" && signers[1].Hash != "hash2" { + t.Fatal("Signers are not correctly added") + } +} + +func helperCompareInformations(t *testing.T, contract, fetched Contract) { + if contract.Date.Unix() != fetched.Date.Unix() || contract.Comment != fetched.Comment || contract.Ready != fetched.Ready || len(contract.Signers) != len(fetched.Signers) { + t.Fatal("Contract informations doesn't match") + } +} + +// Insert a contract with 2 users and check the fields are correctly persisted +func TestInsertContract(t *testing.T) { + contract := NewContract() + contract.AddSigner("mail1", "hash1") + contract.AddSigner("mail1", "hash1") + contract.File.Name = "file" + contract.File.Hash = "hashFile" + contract.File.Hosted = false + contract.Comment = "comment" + contract.Ready = true + + _, err := repository.Collection.Insert(contract) + if err != nil { + t.Fatal("Contract not inserted successfully in the database") + } + + fmt.Println("Successfully persisted contract") + + fetched := Contract{} + selector := Contract{ + ID: contract.ID, + } + err = repository.Collection.FindByID(selector, &fetched) + + if err != nil { + t.Fatal("Contract could not be successfully retrieved") + } + + helperCompareFiles(t, *contract, fetched) + helperCompareInformations(t, *contract, fetched) + + if contract.Signers[0].Hash != fetched.Signers[0].Hash || contract.Signers[0].Hash != fetched.Signers[1].Hash { + t.Fatal("Signers hash doesn't match") + } + if contract.Signers[0].Email != fetched.Signers[0].Email || contract.Signers[0].Email != fetched.Signers[1].Email { + t.Fatal("Signers hash doesn't match") + } + if contract.Signers[0].UserID != fetched.Signers[0].UserID || contract.Signers[1].UserID != fetched.Signers[1].UserID { + t.Fatal("Signers id doesn't match") + } + fmt.Println("Successfully fetched contract") +} diff --git a/dfssp/user/entity.go b/dfssp/user/entity.go new file mode 100644 index 0000000..f57c726 --- /dev/null +++ b/dfssp/user/entity.go @@ -0,0 +1,65 @@ +package user + +import ( + "dfss/mgdb" + + "time" + + "gopkg.in/mgo.v2/bson" +) + +// ConnectionInfo : Internal connection information of a User +type ConnectionInfo struct { + IP string `key:"ip" bson:"ip"` // Ip of the connection + Port int `key:"port" bson:"port"` // Port of the connection +} + +// NewConnectionInfo : Create a new ConnectionInfo +func NewConnectionInfo() *ConnectionInfo { + return &ConnectionInfo{} +} + +// User : User stored in mongo +type User struct { + ID bson.ObjectId `key:"_id" bson:"_id"` // Internal id of a User + Email string `key:"email" bson:"email"` // Email of a User + Registration time.Time `key:"registration" bson:"registration"` // Time of registration of the User + RegToken string `key:"regToken" bson:"regToken"` // Token used for registering a User + Csr string `key:"csr" bson:"csr"` // Certificate request at PEM format + Certificate string `key:"certificate" bson:"certificate"` // Certificate of the User + CertHash string `key:"certHash" bson:"certHash"` // Hash of the certificate + ConnInfo ConnectionInfo `key:"connInfo" bson:"connInfo"` // Information about the connection +} + +// NewUser : Create a new User +func NewUser() *User { + return &User{ + ID: bson.NewObjectId(), + Registration: time.Now().UTC(), + ConnInfo: *NewConnectionInfo(), + } +} + +// Repository : Holds all the complex methods regarding a user +type Repository struct { + Collection *mgdb.MongoCollection +} + +// NewRepository : Creates a new user repository from the given connection +func NewRepository(collection *mgdb.MongoCollection) *Repository { + return &Repository{ + collection, + } +} + +// FetchByMailAndHash : Fetches a User from its email and certificate hash +func (repository *Repository) FetchByMailAndHash(email, hash string) (*User, error) { + var users []User + err := repository.Collection.FindAll(bson.M{"email": email, "certHash": hash}, &users) + if err != nil || len(users) == 0 { + return nil, err + } + + users[0].Registration = users[0].Registration.UTC() + return &users[0], err +} diff --git a/dfssp/user/entity_test.go b/dfssp/user/entity_test.go new file mode 100644 index 0000000..3b4158b --- /dev/null +++ b/dfssp/user/entity_test.go @@ -0,0 +1,151 @@ +package user + +import ( + "dfss/mgdb" + "fmt" + "os" + "testing" + + "gopkg.in/mgo.v2/bson" +) + +var err error +var collection *mgdb.MongoCollection +var manager *mgdb.MongoManager +var dbURI string + +var repository *Repository + +func TestMain(m *testing.M) { + + dbURI = os.Getenv("DFSS_MONGO_URI") + if dbURI == "" { + dbURI = "mongodb://localhost/dfss" + } + + manager, err = mgdb.NewManager(dbURI) + collection = manager.Get("demo") + + repository = NewRepository(collection) + + // Run + code := m.Run() + + // Teardown + // The collection is created automatically on + // first connection, that's why we do not recreate it manually + err = collection.Drop() + + if err != nil { + fmt.Println("An error occurred while droping the collection") + } + manager.Close() + + os.Exit(code) +} + +func TestMongoFetchInexistantUser(t *testing.T) { + user, erro := repository.FetchByMailAndHash("dummyMail", "dummyHash") + if user != nil || erro != nil { + t.Fatal("User should not have been found and error should be nil") + } +} + +func TestMongoInsertUser(t *testing.T) { + user := NewUser() + user.Email = "dfss1@mpcs.tk" + user.CertHash = "dummy_hash" + user.ConnInfo.IP = "127.0.0.1" + user.ConnInfo.Port = 1111 + user.Csr = "csr1" + user.RegToken = "regToken 1" + + _, err = repository.Collection.Insert(user) + if err != nil { + t.Fatal("An error occurred while inserting the user") + } + + fmt.Println("Successfully inserted a user") +} + +func equalUsers(t *testing.T, user1, user2 *User) { + if user1.ID != user2.ID { + t.Fatal("ID doesn't match : received ", user1.ID, " and ", user2.ID) + } + + if user1.CertHash != user2.CertHash { + t.Fatal("CertHash doesn't match : received ", user1.CertHash, " and ", user2.CertHash) + } + + if user1.Email != user2.Email { + t.Fatal("Email doesn't match : received ", user1.Email, " and ", user2.Email) + } + + if user1.Registration.Unix() != user2.Registration.Unix() { + t.Fatal("Registration doesn't match : received ", user1.Registration, " and ", user2.Registration) + } + + if user1.RegToken != user2.RegToken { + t.Fatal("RegToken doesn't match : received ", user1.RegToken, " and ", user2.RegToken) + } + + if user1.Csr != user2.Csr { + t.Fatal("Csr doesn't match : received ", user1.Csr, " and ", user2.Csr) + } + + if user1.ConnInfo.IP != user2.ConnInfo.IP { + t.Fatal("ConnInfo.IP doesn't match : received ", user1.ConnInfo.IP, " and ", user2.ConnInfo.IP) + } + + if user1.ConnInfo.Port != user2.ConnInfo.Port { + t.Fatal("ConnInfo.Port doesn't match : received ", user1.ConnInfo.Port, " and ", user2.ConnInfo.Port) + } + + if user1.Certificate != user2.Certificate { + t.Fatal("Certificate doesn't match : received ", user1.Certificate, " and ", user2.Certificate) + } +} + +func TestMongoFetchUser(t *testing.T) { + user := NewUser() + user.Email = "dfss2@mpcs.tk" + user.CertHash = "dummy_hash" + user.ConnInfo.IP = "127.0.0.2" + user.ConnInfo.Port = 2222 + user.Csr = "csr2" + user.RegToken = "regToken 2" + + _, err = repository.Collection.Insert(user) + + if err != nil { + t.Fatal("An error occured while inserting a user: ", err) + } + + fetched, erro := repository.FetchByMailAndHash(user.Email, user.CertHash) + + if erro != nil { + t.Fatal("An error occurred while fetching the previously inserted user", err) + } + + equalUsers(t, user, fetched) +} + +func TestMongoFetchIncompleteUser(t *testing.T) { + user := User{ + ID: bson.NewObjectId(), + } + + _, err = repository.Collection.Insert(user) + + if err != nil { + t.Fatal("An error occured while inserting a user: ", err) + } + + fetched, erro := repository.FetchByMailAndHash(user.Email, user.CertHash) + + if erro != nil { + t.Fatal("An error occurred while fetching the previously inserted user", err) + } + + equalUsers(t, &user, fetched) +} -- GitLab