Update quiz using file store
This commit is contained in:
parent
7a1135de0f
commit
8817d2d314
10 changed files with 290 additions and 72 deletions
18
models/models_test.go
Normal file
18
models/models_test.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/remogatto/prettytest"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testSuite struct {
|
||||||
|
prettytest.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner(t *testing.T) {
|
||||||
|
prettytest.Run(
|
||||||
|
t,
|
||||||
|
new(testSuite),
|
||||||
|
)
|
||||||
|
}
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.andreafazzi.eu/andrea/probo/client"
|
"git.andreafazzi.eu/andrea/probo/client"
|
||||||
"git.andreafazzi.eu/andrea/probo/hasher/sha256"
|
"git.andreafazzi.eu/andrea/probo/hasher/sha256"
|
||||||
|
@ -20,16 +22,30 @@ type FileProboCollectorStore struct {
|
||||||
|
|
||||||
memoryStore *memory.MemoryProboCollectorStore
|
memoryStore *memory.MemoryProboCollectorStore
|
||||||
paths map[string]string
|
paths map[string]string
|
||||||
|
|
||||||
|
// A mutex is used to synchronize read/write access to the map
|
||||||
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileProboCollectorStore(dirname string) (*FileProboCollectorStore, error) {
|
func NewFileProboCollectorStore(dirname string) (*FileProboCollectorStore, error) {
|
||||||
s := new(FileProboCollectorStore)
|
s := new(FileProboCollectorStore)
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(dirname)
|
s.Dir = dirname
|
||||||
|
|
||||||
|
err := s.Reindex()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FileProboCollectorStore) Reindex() error {
|
||||||
|
files, err := ioutil.ReadDir(s.Dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
s.paths = make(map[string]string)
|
s.paths = make(map[string]string)
|
||||||
|
|
||||||
markdownFiles := make([]fs.FileInfo, 0)
|
markdownFiles := make([]fs.FileInfo, 0)
|
||||||
|
@ -42,7 +58,7 @@ func NewFileProboCollectorStore(dirname string) (*FileProboCollectorStore, error
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(markdownFiles) == 0 {
|
if len(markdownFiles) == 0 {
|
||||||
return nil, fmt.Errorf("The directory is empty.")
|
return fmt.Errorf("The directory is empty.")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memoryStore = memory.NewMemoryProboCollectorStore(
|
s.memoryStore = memory.NewMemoryProboCollectorStore(
|
||||||
|
@ -51,24 +67,27 @@ func NewFileProboCollectorStore(dirname string) (*FileProboCollectorStore, error
|
||||||
|
|
||||||
for _, file := range markdownFiles {
|
for _, file := range markdownFiles {
|
||||||
filename := file.Name()
|
filename := file.Name()
|
||||||
fullPath := filepath.Join(dirname, filename)
|
fullPath := filepath.Join(s.Dir, filename)
|
||||||
|
|
||||||
content, err := os.ReadFile(fullPath)
|
content, err := os.ReadFile(fullPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
quiz, err := QuizFromMarkdown(string(content))
|
quiz, err := QuizFromMarkdown(string(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
s.memoryStore.CreateQuiz(&client.CreateUpdateQuizRequest{
|
q, err := s.memoryStore.CreateQuiz(&client.CreateUpdateQuizRequest{
|
||||||
Quiz: quiz,
|
Quiz: quiz,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Dir = dirname
|
s.SetPath(q, fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
return s, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileProboCollectorStore) ReadAllQuizzes() ([]*models.Quiz, error) {
|
func (s *FileProboCollectorStore) ReadAllQuizzes() ([]*models.Quiz, error) {
|
||||||
|
@ -86,7 +105,12 @@ func (s *FileProboCollectorStore) CreateQuiz(r *client.CreateUpdateQuizRequest)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return quiz, nil
|
err = s.Reindex()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.memoryStore.ReadQuizByHash(quiz.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileProboCollectorStore) UpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) {
|
func (s *FileProboCollectorStore) UpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) {
|
||||||
|
@ -95,7 +119,35 @@ func (s *FileProboCollectorStore) UpdateQuiz(r *client.CreateUpdateQuizRequest,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return quiz, nil
|
err = s.createOrUpdateMarkdownFile(quiz)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.Reindex()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.memoryStore.ReadQuizByHash(quiz.Hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FileProboCollectorStore) GetPath(quiz *models.Quiz) (string, error) {
|
||||||
|
s.lock.RLock()
|
||||||
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
|
path, ok := s.paths[quiz.ID]
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New(fmt.Sprintf("Path not found for quiz ID %v", quiz.ID))
|
||||||
|
}
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FileProboCollectorStore) SetPath(quiz *models.Quiz, path string) string {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
s.paths[quiz.ID] = path
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func MarkdownFromQuiz(quiz *models.Quiz) (string, error) {
|
func MarkdownFromQuiz(quiz *models.Quiz) (string, error) {
|
||||||
|
@ -103,20 +155,22 @@ func MarkdownFromQuiz(quiz *models.Quiz) (string, error) {
|
||||||
return "", errors.New("Quiz should contain a question but it wasn't provided.")
|
return "", errors.New("Quiz should contain a question but it wasn't provided.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(quiz.Answers) == 0 {
|
if len(quiz.Answers) < 2 {
|
||||||
return "", errors.New("Quiz should contain at least 2 answers but none was provided.")
|
return "", errors.New("Quiz should contain at least 2 answers but none was provided.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if quiz.Correct == nil {
|
if quiz.Correct == nil {
|
||||||
return "", errors.New("Quiz should contain a correct answer but non was provided.")
|
return "", errors.New("Quiz should contain a correct answer but not was provided.")
|
||||||
}
|
}
|
||||||
|
|
||||||
correctAnswer := "* " + quiz.Correct.Text
|
correctAnswer := "* " + quiz.Correct.Text
|
||||||
var otherAnswers string
|
var otherAnswers string
|
||||||
|
|
||||||
for _, answer := range quiz.Answers {
|
for _, answer := range quiz.Answers {
|
||||||
|
if quiz.Correct != answer {
|
||||||
otherAnswers += "* " + answer.Text + "\n"
|
otherAnswers += "* " + answer.Text + "\n"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
markdown := quiz.Question.Text + "\n\n" + correctAnswer + "\n" + otherAnswers
|
markdown := quiz.Question.Text + "\n\n" + correctAnswer + "\n" + otherAnswers
|
||||||
|
|
||||||
|
@ -160,20 +214,21 @@ func QuizFromMarkdown(markdown string) (*client.Quiz, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileProboCollectorStore) createOrUpdateMarkdownFile(quiz *models.Quiz) error {
|
func (s *FileProboCollectorStore) createOrUpdateMarkdownFile(quiz *models.Quiz) error {
|
||||||
var filename string
|
|
||||||
|
|
||||||
markdown, err := MarkdownFromQuiz(quiz)
|
markdown, err := MarkdownFromQuiz(quiz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fn := s.paths[quiz.ID]
|
|
||||||
|
fn, _ := s.GetPath(quiz)
|
||||||
if fn == "" {
|
if fn == "" {
|
||||||
filename = filepath.Join(s.Dir, quiz.Hash+".md")
|
fn = filepath.Join(s.Dir, fmt.Sprintf("quiz_%v.%s", time.Now().Unix(), "md"))
|
||||||
}
|
}
|
||||||
file, err := os.Create(filename)
|
|
||||||
|
file, err := os.Create(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
_, err = file.Write([]byte(markdown))
|
_, err = file.Write([]byte(markdown))
|
||||||
|
@ -181,20 +236,7 @@ func (s *FileProboCollectorStore) createOrUpdateMarkdownFile(quiz *models.Quiz)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.SetPath(quiz, fn)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (s *FileProboCollectorStore) writeMarkdownFile(quiz *models.Quiz) error {
|
|
||||||
// markdown, err := MarkdownFromQuiz(quiz)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// filename := filepath.Join(s.Dir, quiz.Hash+".md")
|
|
||||||
// err = ioutil.WriteFile(filename, []byte(markdown), 0644)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
|
@ -3,12 +3,13 @@ package file
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.andreafazzi.eu/andrea/probo/client"
|
"git.andreafazzi.eu/andrea/probo/client"
|
||||||
|
"git.andreafazzi.eu/andrea/probo/hasher/sha256"
|
||||||
"git.andreafazzi.eu/andrea/probo/models"
|
"git.andreafazzi.eu/andrea/probo/models"
|
||||||
|
"git.andreafazzi.eu/andrea/probo/store/memory"
|
||||||
"github.com/remogatto/prettytest"
|
"github.com/remogatto/prettytest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ Question text (3).
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testSuite) TestReadAllQuizzes() {
|
func (t *testSuite) TestReadAllQuizzes() {
|
||||||
store, err := NewFileProboCollectorStore("./test/quizzes")
|
store, err := NewFileProboCollectorStore("./testdata/quizzes")
|
||||||
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
|
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
|
||||||
|
|
||||||
if !t.Failed() {
|
if !t.Failed() {
|
||||||
|
@ -68,19 +69,14 @@ func (t *testSuite) TestReadAllQuizzes() {
|
||||||
len(result),
|
len(result),
|
||||||
fmt.Sprintf("The store contains 3 files but only 2 should be parsed (duplicated quiz). Total of parsed quizzes are instead %v", len(result)),
|
fmt.Sprintf("The store contains 3 files but only 2 should be parsed (duplicated quiz). Total of parsed quizzes are instead %v", len(result)),
|
||||||
)
|
)
|
||||||
t.Equal("Question text 1.", result[0].Question.Text)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testSuite) TestCreateQuiz() {
|
func (t *testSuite) TestMarkdownFromQuiz() {
|
||||||
dirname := "./test/quizzes"
|
store := memory.NewMemoryProboCollectorStore(sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn))
|
||||||
store, err := NewFileProboCollectorStore(dirname)
|
quiz, err := store.CreateQuiz(
|
||||||
|
|
||||||
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
|
|
||||||
|
|
||||||
_, err = store.CreateQuiz(
|
|
||||||
&client.CreateUpdateQuizRequest{
|
&client.CreateUpdateQuizRequest{
|
||||||
Quiz: &client.Quiz{
|
Quiz: &client.Quiz{
|
||||||
Question: &client.Question{Text: "Newly created question text."},
|
Question: &client.Question{Text: "Newly created question text."},
|
||||||
|
@ -92,25 +88,70 @@ func (t *testSuite) TestCreateQuiz() {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
md, err := MarkdownFromQuiz(quiz)
|
||||||
|
t.Nil(err, "Conversion to markdown should not raise an error")
|
||||||
|
if !t.Failed() {
|
||||||
|
t.Equal(`Newly created question text.
|
||||||
|
|
||||||
|
* Answer 1
|
||||||
|
* Answer 2
|
||||||
|
* Answer 3
|
||||||
|
* Answer 4
|
||||||
|
`, md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testSuite) TestCreateQuiz() {
|
||||||
|
dirname := "./testdata/quizzes"
|
||||||
|
store, err := NewFileProboCollectorStore(dirname)
|
||||||
|
|
||||||
|
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
|
||||||
|
|
||||||
|
if !t.Failed() {
|
||||||
|
clientQuiz := &client.Quiz{
|
||||||
|
Question: &client.Question{Text: "Newly created question text."},
|
||||||
|
Answers: []*client.Answer{
|
||||||
|
{Text: "Answer 1", Correct: true},
|
||||||
|
{Text: "Answer 2", Correct: false},
|
||||||
|
{Text: "Answer 3", Correct: false},
|
||||||
|
{Text: "Answer 4", Correct: false},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
quiz, err := store.CreateQuiz(
|
||||||
|
&client.CreateUpdateQuizRequest{
|
||||||
|
Quiz: clientQuiz,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
t.Nil(err, fmt.Sprintf("An error was raised when saving the quiz on disk: %v", err))
|
t.Nil(err, fmt.Sprintf("An error was raised when saving the quiz on disk: %v", err))
|
||||||
|
|
||||||
newFilename := filepath.Join(
|
if !t.Failed() {
|
||||||
dirname,
|
path, err := store.GetPath(quiz)
|
||||||
"94ed4e9cdf8e0a75a2c5ce925cb791ebc5977ce1801e12059f58ce4d66c0c7f6.md",
|
t.Nil(err, "GetPath should not raise an error.")
|
||||||
)
|
|
||||||
exists, err := os.Stat(newFilename)
|
if !t.Failed() {
|
||||||
|
exists, err := os.Stat(path)
|
||||||
t.Nil(err, "Stat should not return an error")
|
t.Nil(err, "Stat should not return an error")
|
||||||
|
|
||||||
if !t.Failed() {
|
if !t.Failed() {
|
||||||
t.True(exists != nil, "The new quiz file was not created.")
|
t.True(exists != nil, "The new quiz file was not created.")
|
||||||
err := os.Remove(newFilename)
|
if !t.Failed() {
|
||||||
t.Nil(err, "Stat should not return an error")
|
quizFromDisk, err := readQuizFromDisk(path)
|
||||||
|
t.Nil(err, "Quiz should be read from disk without errors.")
|
||||||
|
if !t.Failed() {
|
||||||
|
t.True(reflect.DeepEqual(quizFromDisk, clientQuiz), "Quiz read from disk and stored in memory should be equal.")
|
||||||
|
err := os.Remove(path)
|
||||||
|
t.Nil(err, "Test file should be removed without errors.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testSuite) TestUpdateQuiz() {
|
func (t *testSuite) TestUpdateQuiz() {
|
||||||
dirname := "./test/quizzes"
|
dirname := "./testdata/quizzes"
|
||||||
store, err := NewFileProboCollectorStore(dirname)
|
store, err := NewFileProboCollectorStore(dirname)
|
||||||
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
|
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
|
||||||
|
|
||||||
|
@ -130,18 +171,40 @@ func (t *testSuite) TestUpdateQuiz() {
|
||||||
t.Nil(err, "The quiz to be updated should be created without issue")
|
t.Nil(err, "The quiz to be updated should be created without issue")
|
||||||
|
|
||||||
if !t.Failed() {
|
if !t.Failed() {
|
||||||
_, err = store.UpdateQuiz(
|
clientQuiz := &client.Quiz{
|
||||||
&client.CreateUpdateQuizRequest{
|
Question: &client.Question{Text: "Newly created question text."},
|
||||||
Quiz: &client.Quiz{
|
|
||||||
Question: &client.Question{Text: "Updated question text."},
|
|
||||||
Answers: []*client.Answer{
|
Answers: []*client.Answer{
|
||||||
{Text: "Answer 1", Correct: true},
|
{Text: "Answer 1", Correct: true},
|
||||||
{Text: "Answer 2", Correct: false},
|
{Text: "Answer 2", Correct: false},
|
||||||
{Text: "Answer 3", Correct: false},
|
{Text: "Answer 3", Correct: false},
|
||||||
{Text: "Answer 4", Correct: false},
|
{Text: "Answer 4", Correct: false},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
|
||||||
|
updatedQuiz, err := store.UpdateQuiz(
|
||||||
|
&client.CreateUpdateQuizRequest{
|
||||||
|
Quiz: clientQuiz,
|
||||||
}, quiz.ID)
|
}, quiz.ID)
|
||||||
|
|
||||||
|
t.Nil(err, fmt.Sprintf("Quiz should be updated without errors: %v", err))
|
||||||
|
|
||||||
|
if !t.Failed() {
|
||||||
|
path, err := store.GetPath(updatedQuiz)
|
||||||
|
|
||||||
|
if !t.Failed() {
|
||||||
|
t.Nil(err, "GetPath should not raise an error.")
|
||||||
|
|
||||||
|
if !t.Failed() {
|
||||||
|
quizFromDisk, err := readQuizFromDisk(path)
|
||||||
|
t.Nil(err, "Quiz should be read from disk without errors.")
|
||||||
|
if !t.Failed() {
|
||||||
|
t.True(reflect.DeepEqual(clientQuiz, quizFromDisk), "Quiz should be updated.")
|
||||||
|
err := os.Remove(path)
|
||||||
|
t.Nil(err, "Stat should not return an error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +215,14 @@ func createQuizOnDisk(store *FileProboCollectorStore, req *client.CreateUpdateQu
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readQuizFromDisk(path string) (*client.Quiz, error) {
|
||||||
|
content, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return QuizFromMarkdown(string(content))
|
||||||
|
}
|
||||||
|
|
||||||
func testsAreEqual(got, want []*models.Quiz) bool {
|
func testsAreEqual(got, want []*models.Quiz) bool {
|
||||||
return reflect.DeepEqual(got, want)
|
return reflect.DeepEqual(got, want)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
Newly created question text.
|
|
||||||
|
|
||||||
* Answer 1
|
|
||||||
* Answer 1
|
|
||||||
* Answer 2
|
|
||||||
* Answer 3
|
|
||||||
* Answer 4
|
|
|
@ -124,7 +124,21 @@ func (s *MemoryProboCollectorStore) ReadAllQuizzes() ([]*models.Quiz, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *MemoryProboCollectorStore) ReadQuizByHash(hash string) (*models.Quiz, error) {
|
||||||
|
quiz := s.getQuizFromHash(hash)
|
||||||
|
if quiz == nil {
|
||||||
|
return nil, fmt.Errorf("Quiz with hash %s was not found in the store.", hash)
|
||||||
|
}
|
||||||
|
return quiz, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MemoryProboCollectorStore) CalculateQuizHash(quiz *client.Quiz) string {
|
||||||
|
hashes := s.hasher.QuizHashes(quiz)
|
||||||
|
return hashes[len(hashes)-1]
|
||||||
|
}
|
||||||
|
|
||||||
func (s *MemoryProboCollectorStore) createOrUpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) {
|
func (s *MemoryProboCollectorStore) createOrUpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error) {
|
||||||
|
|
||||||
hashes := s.hasher.QuizHashes(r.Quiz)
|
hashes := s.hasher.QuizHashes(r.Quiz)
|
||||||
quizHash := hashes[len(hashes)-1]
|
quizHash := hashes[len(hashes)-1]
|
||||||
|
|
||||||
|
|
78
store/memory/memory_test.go
Normal file
78
store/memory/memory_test.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package memory
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.andreafazzi.eu/andrea/probo/client"
|
||||||
|
"git.andreafazzi.eu/andrea/probo/hasher/sha256"
|
||||||
|
"github.com/remogatto/prettytest"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testSuite struct {
|
||||||
|
prettytest.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner(t *testing.T) {
|
||||||
|
prettytest.Run(
|
||||||
|
t,
|
||||||
|
new(testSuite),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testSuite) TestReadQuizByHash() {
|
||||||
|
store := NewMemoryProboCollectorStore(
|
||||||
|
sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn),
|
||||||
|
)
|
||||||
|
quiz, _ := store.CreateQuiz(
|
||||||
|
&client.CreateUpdateQuizRequest{
|
||||||
|
Quiz: &client.Quiz{
|
||||||
|
Question: &client.Question{Text: "Newly created question text."},
|
||||||
|
Answers: []*client.Answer{
|
||||||
|
{Text: "Answer 1", Correct: true},
|
||||||
|
{Text: "Answer 2", Correct: false},
|
||||||
|
{Text: "Answer 3", Correct: false},
|
||||||
|
{Text: "Answer 4", Correct: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
quizFromMemory, err := store.ReadQuizByHash(quiz.Hash)
|
||||||
|
t.Nil(err, "Quiz should be found in the store")
|
||||||
|
if !t.Failed() {
|
||||||
|
t.True(reflect.DeepEqual(quizFromMemory, quiz), "Quiz should be equal")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testSuite) TestUpdateQuiz() {
|
||||||
|
store := NewMemoryProboCollectorStore(
|
||||||
|
sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn),
|
||||||
|
)
|
||||||
|
quiz, _ := store.CreateQuiz(
|
||||||
|
&client.CreateUpdateQuizRequest{
|
||||||
|
Quiz: &client.Quiz{
|
||||||
|
Question: &client.Question{Text: "Newly created question text."},
|
||||||
|
Answers: []*client.Answer{
|
||||||
|
{Text: "Answer 1", Correct: true},
|
||||||
|
{Text: "Answer 2", Correct: false},
|
||||||
|
{Text: "Answer 3", Correct: false},
|
||||||
|
{Text: "Answer 4", Correct: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
updatedQuiz, _ := store.CreateQuiz(
|
||||||
|
&client.CreateUpdateQuizRequest{
|
||||||
|
Quiz: &client.Quiz{
|
||||||
|
Question: &client.Question{Text: "Updated question text."},
|
||||||
|
Answers: []*client.Answer{
|
||||||
|
{Text: "Answer 1", Correct: true},
|
||||||
|
{Text: "Answer 2", Correct: false},
|
||||||
|
{Text: "Answer 3", Correct: false},
|
||||||
|
{Text: "Answer 4", Correct: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
t.True(quiz.Hash != updatedQuiz.Hash, "The two hashes should not be equal.")
|
||||||
|
}
|
|
@ -8,6 +8,8 @@ import (
|
||||||
type ProboCollectorStore interface {
|
type ProboCollectorStore interface {
|
||||||
ReadAllQuizzes() ([]*models.Quiz, error)
|
ReadAllQuizzes() ([]*models.Quiz, error)
|
||||||
|
|
||||||
|
ReadQuizByHash(hash string) (*models.Quiz, error)
|
||||||
|
|
||||||
CreateQuiz(r *client.CreateUpdateQuizRequest) (*models.Quiz, error)
|
CreateQuiz(r *client.CreateUpdateQuizRequest) (*models.Quiz, error)
|
||||||
UpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error)
|
UpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue