Collections

This commit is contained in:
andrea 2023-10-07 11:43:12 +02:00
parent 4da6162dd4
commit 15830d888f
10 changed files with 474 additions and 115 deletions

View file

@ -16,6 +16,11 @@ type Quiz struct {
Answers []*Answer `json:"answers"`
}
type Collection struct {
Name string `json:"name"`
Query string `json:"query"`
}
type BaseResponse struct {
Status string `json:"status"`
Message string `json:"message"`
@ -52,3 +57,11 @@ type CreateUpdateQuizRequest struct {
type DeleteQuizRequest struct {
ID string
}
type CreateUpdateCollectionRequest struct {
*Collection
}
type DeleteCollectionRequest struct {
ID string
}

9
models/collection.go Normal file
View file

@ -0,0 +1,9 @@
package models
type Collection struct {
ID string `json:"id"`
Name string `json:"name"`
Query string `json:"query"`
IDs []string `json:"ids"`
}

View file

@ -5,5 +5,5 @@ import "time"
type Meta struct {
ID string `json:"id" yaml:"id"`
CreatedAt time.Time `json:"created_at" yaml:"created_at"`
Tags []*Tag `json:"tags" yaml:"tags"`
Tags []*Tag `json:"tags" yaml:"-"`
}

View file

@ -0,0 +1,98 @@
package file
import (
"fmt"
"os"
"git.andreafazzi.eu/andrea/probo/client"
"github.com/remogatto/prettytest"
)
type collectionTestSuite struct {
prettytest.Suite
}
func (t *collectionTestSuite) TestCreateCollection() {
store, err := NewFileProboCollectorStore(testdataDir)
t.Nil(err, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
if !t.Failed() {
quiz_1, err := createQuizOnDisk(store, &client.CreateUpdateQuizRequest{
Quiz: &client.Quiz{
Question: &client.Question{Text: "Question text with #tag1."},
Answers: []*client.Answer{
{Text: "Answer 1", Correct: true},
{Text: "Answer 2", Correct: false},
{Text: "Answer 3", Correct: false},
{Text: "Answer 4", Correct: false},
},
},
})
t.Nil(err, "The quiz to be updated should be created without issue")
path_1, _ := store.GetQuizPath(quiz_1)
if !t.Failed() {
quiz_2, err := createQuizOnDisk(store, &client.CreateUpdateQuizRequest{
Quiz: &client.Quiz{
Question: &client.Question{Text: "Another question text with #tag1."},
Answers: []*client.Answer{
{Text: "Answer 1", Correct: true},
{Text: "Answer 2", Correct: false},
{Text: "Answer 3", Correct: false},
{Text: "Answer 4", Correct: false},
},
},
})
t.Nil(err, "The quiz to be updated should be created without issue")
path_2, _ := store.GetQuizPath(quiz_2)
if !t.Failed() {
quiz_3, err := createQuizOnDisk(store, &client.CreateUpdateQuizRequest{
Quiz: &client.Quiz{
Question: &client.Question{Text: "Question text without tags."},
Answers: []*client.Answer{
{Text: "Answer 1", Correct: true},
{Text: "Answer 2", Correct: false},
{Text: "Answer 3", Correct: false},
{Text: "Answer 4", Correct: false},
},
},
})
t.Nil(err, "The quiz to be updated should be created without issue")
path_3, _ := store.GetQuizPath(quiz_3)
if !t.Failed() {
collection, err := store.CreateCollection(
&client.CreateUpdateCollectionRequest{
Collection: &client.Collection{
Name: "MyCollection",
Query: "#tag1",
},
})
t.Nil(err, "Creating a collection should not return an error")
collectionPath, _ := store.GetCollectionPath(collection)
if !t.Failed() {
t.Equal(2, len(collection.IDs))
os.Remove(path_1)
os.Remove(path_2)
os.Remove(path_3)
os.Remove(collectionPath)
}
}
}
}
}
}

View file

@ -3,6 +3,7 @@ package file
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
@ -22,13 +23,23 @@ import (
"github.com/go-yaml/yaml"
)
var ErrorMetaHeaderIsNotPresent = errors.New("Meta header was not found in file.")
var (
ErrorMetaHeaderIsNotPresent = errors.New("Meta header was not found in file.")
DefaultQuizzesDir = "quizzes"
DefaultCollectionsDir = "collections"
)
type FileProboCollectorStore struct {
Dir string
memoryStore *memory.MemoryProboCollectorStore
paths map[string]string
quizzesPaths map[string]string
collectionsPaths map[string]string
quizzesDir string
collectionsDir string
// A mutex is used to synchronize read/write access to the map
lock sync.RWMutex
@ -39,6 +50,9 @@ func NewFileProboCollectorStore(dirname string) (*FileProboCollectorStore, error
s.Dir = dirname
s.quizzesDir = filepath.Join(s.Dir, DefaultQuizzesDir)
s.collectionsDir = filepath.Join(s.Dir, DefaultCollectionsDir)
err := s.Reindex()
if err != nil {
return nil, err
@ -47,14 +61,20 @@ func NewFileProboCollectorStore(dirname string) (*FileProboCollectorStore, error
return s, nil
}
func (s *FileProboCollectorStore) Reindex() error {
files, err := ioutil.ReadDir(s.Dir)
func (s *FileProboCollectorStore) GetQuizzesDir() string {
return s.quizzesDir
}
func (s *FileProboCollectorStore) GetCollectionsDir() string {
return s.collectionsDir
}
func (s *FileProboCollectorStore) reindexQuizzes() error {
files, err := ioutil.ReadDir(s.quizzesDir)
if err != nil {
return err
}
s.paths = make(map[string]string)
markdownFiles := make([]fs.FileInfo, 0)
for _, file := range files {
@ -68,13 +88,9 @@ func (s *FileProboCollectorStore) Reindex() error {
return fmt.Errorf("The directory is empty.")
}
s.memoryStore = memory.NewMemoryProboCollectorStore(
sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn),
)
for _, file := range markdownFiles {
filename := file.Name()
fullPath := filepath.Join(s.Dir, filename)
fullPath := filepath.Join(s.quizzesDir, filename)
content, err := os.ReadFile(fullPath)
if err != nil {
@ -98,7 +114,72 @@ func (s *FileProboCollectorStore) Reindex() error {
CreatedAt: time.Now(),
})
}
s.SetPath(q, fullPath)
s.SetQuizPath(q, fullPath)
}
return nil
}
func (s *FileProboCollectorStore) reindexCollections() error {
files, err := ioutil.ReadDir(s.collectionsDir)
if err != nil {
return err
}
jsonFiles := make([]fs.FileInfo, 0)
for _, file := range files {
filename := file.Name()
if !file.IsDir() && strings.HasSuffix(filename, ".json") {
jsonFiles = append(jsonFiles, file)
}
}
for _, file := range jsonFiles {
filename := file.Name()
fullPath := filepath.Join(s.collectionsDir, filename)
content, err := os.ReadFile(fullPath)
if err != nil {
return err
}
var clientCollection *client.Collection
err = json.Unmarshal(content, &clientCollection)
if err != nil {
return err
}
collection, err := s.memoryStore.CreateCollection(&client.CreateUpdateCollectionRequest{
Collection: clientCollection,
})
if err != nil {
return err
}
s.SetCollectionPath(collection, fullPath)
}
return nil
}
func (s *FileProboCollectorStore) Reindex() error {
s.memoryStore = memory.NewMemoryProboCollectorStore(
sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn),
)
s.quizzesPaths = make(map[string]string)
s.collectionsPaths = make(map[string]string)
err := s.reindexQuizzes()
if err != nil {
return err
}
err = s.reindexCollections()
if err != nil {
return err
}
return nil
@ -153,7 +234,7 @@ func (s *FileProboCollectorStore) DeleteQuiz(r *client.DeleteQuizRequest) (*mode
return nil, err
}
path, err := s.GetPath(quiz)
path, err := s.GetQuizPath(quiz)
if err != nil {
return nil, err
}
@ -171,21 +252,47 @@ func (s *FileProboCollectorStore) DeleteQuiz(r *client.DeleteQuizRequest) (*mode
return quiz, nil
}
func (s *FileProboCollectorStore) GetPath(quiz *models.Quiz) (string, error) {
func (s *FileProboCollectorStore) GetQuizPath(quiz *models.Quiz) (string, error) {
if quiz == nil {
return "", errors.New("Quiz object passed as argument is nil!")
}
s.lock.RLock()
defer s.lock.RUnlock()
path, ok := s.paths[quiz.ID]
path, ok := s.quizzesPaths[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 {
func (s *FileProboCollectorStore) GetCollectionPath(collection *models.Collection) (string, error) {
s.lock.RLock()
defer s.lock.RUnlock()
path, ok := s.collectionsPaths[collection.ID]
if !ok {
return "", errors.New(fmt.Sprintf("Path not found for collection ID %v", collection.ID))
}
return path, nil
}
func (s *FileProboCollectorStore) SetQuizPath(quiz *models.Quiz, path string) string {
s.lock.Lock()
defer s.lock.Unlock()
s.paths[quiz.ID] = path
s.quizzesPaths[quiz.ID] = path
return path
}
func (s *FileProboCollectorStore) SetCollectionPath(collection *models.Collection, path string) string {
s.lock.Lock()
defer s.lock.Unlock()
s.collectionsPaths[collection.ID] = path
return path
}
@ -216,67 +323,6 @@ func MarkdownFromQuiz(quiz *models.Quiz) (string, error) {
return markdown, nil
}
// func QuizFromMarkdown(markdown string) (*client.Quiz, *models.Meta, error) {
// meta, remainingMarkdown, err := parseMetaHeaderFromMarkdown(markdown)
// if err != nil {
// return nil, nil, err
// }
// if meta == nil {
// meta = new(models.Meta)
// if meta.Tags == nil {
// meta.Tags = make([]*models.Tag, 0)
// }
// } else if meta.Tags == nil {
// meta.Tags = make([]*models.Tag, 0)
// }
// lines := strings.Split(remainingMarkdown, "\n")
// questionText := ""
// answers := []*client.Answer{}
// for _, line := range lines {
// // Check if the line contains a tag
// if strings.Contains(line, "#") {
// // Split the line into words
// words := strings.Split(line, " ")
// for _, word := range words {
// // If the word starts with '#', add it to the tags
// if strings.HasPrefix(word, "#") {
// meta.Tags = append(meta.Tags, &models.Tag{Name: word[1:]})
// }
// }
// }
// if strings.HasPrefix(line, "*") {
// answerText := strings.TrimPrefix(line, "* ")
// correct := len(answers) == 0
// answer := &client.Answer{Text: answerText, Correct: correct}
// answers = append(answers, answer)
// } else {
// if questionText != "" {
// questionText += "\n"
// }
// questionText += line
// }
// }
// questionText = strings.TrimRight(questionText, "\n")
// if questionText == "" {
// return nil, nil, fmt.Errorf("Question text should not be empty.")
// }
// if len(answers) < 2 {
// return nil, nil, fmt.Errorf("Number of answers should be at least 2 but parsed answers are %d.", len(answers))
// }
// question := &client.Question{Text: questionText}
// quiz := &client.Quiz{Question: question, Answers: answers}
// return quiz, meta, nil
// }
func QuizFromMarkdown(markdown string) (*client.Quiz, *models.Meta, error) {
meta, remainingMarkdown, err := parseMetaHeaderFromMarkdown(markdown)
if err != nil {
@ -319,7 +365,7 @@ func QuizFromMarkdown(markdown string) (*client.Quiz, *models.Meta, error) {
}
func (s *FileProboCollectorStore) ReadMetaHeaderFromFile(filename string) (*models.Meta, error) {
data, err := ioutil.ReadFile(path.Join(s.Dir, filename))
data, err := ioutil.ReadFile(path.Join(s.quizzesDir, filename))
if err != nil {
return nil, err
}
@ -336,7 +382,7 @@ func (s *FileProboCollectorStore) WriteMetaHeaderToFile(filename string, meta *m
return nil, err
}
if readMeta == nil {
_, err := writeMetaHeader(path.Join(s.Dir, filename), meta)
_, err := writeMetaHeader(path.Join(s.quizzesDir, filename), meta)
if err != nil {
return nil, err
}
@ -345,8 +391,22 @@ func (s *FileProboCollectorStore) WriteMetaHeaderToFile(filename string, meta *m
return meta, nil
}
func (s *FileProboCollectorStore) CreateCollection(r *client.CreateUpdateCollectionRequest) (*models.Collection, error) {
collection, err := s.memoryStore.CreateCollection(r)
if err != nil {
return nil, err
}
err = s.createOrUpdateCollectionFile(collection)
if err != nil {
return nil, err
}
return s.memoryStore.ReadCollectionByID(collection.ID)
}
func (s *FileProboCollectorStore) removeMetaFromFile(filename string) (*models.Meta, error) {
file, err := os.Open(path.Join(s.Dir, filename))
file, err := os.Open(path.Join(s.quizzesDir, filename))
if err != nil {
return nil, err
}
@ -399,7 +459,7 @@ func (s *FileProboCollectorStore) removeMetaFromFile(filename string) (*models.M
return nil, err
}
file, err = os.Create(path.Join(s.Dir, filename))
file, err = os.Create(path.Join(s.quizzesDir, filename))
if err != nil {
return nil, err
}
@ -419,15 +479,16 @@ func (s *FileProboCollectorStore) createOrUpdateMarkdownFile(quiz *models.Quiz)
return err
}
fn, _ := s.GetPath(quiz)
fn, _ := s.GetQuizPath(quiz)
if fn == "" {
fn = filepath.Join(s.Dir, fmt.Sprintf("quiz_%v.%s", time.Now().Unix(), "md"))
fn = filepath.Join(s.quizzesDir, fmt.Sprintf("quiz_%v.%s", quiz.ID, "md"))
}
file, err := os.Create(fn)
if err != nil {
return err
}
defer file.Close()
markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta)
@ -440,11 +501,37 @@ func (s *FileProboCollectorStore) createOrUpdateMarkdownFile(quiz *models.Quiz)
return err
}
s.SetPath(quiz, fn)
s.SetQuizPath(quiz, fn)
return nil
}
func (s *FileProboCollectorStore) createOrUpdateCollectionFile(collection *models.Collection) error {
json, err := json.Marshal(collection)
if err != nil {
return err
}
fn, _ := s.GetCollectionPath(collection)
if fn == "" {
fn = filepath.Join(s.collectionsDir, fmt.Sprintf("collection_%v.%s", collection.ID, "json"))
}
file, err := os.Create(fn)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write([]byte(json))
if err != nil {
return err
}
s.SetCollectionPath(collection, fn)
return nil
}
func addMetaHeaderToMarkdown(content string, meta *models.Meta) (string, error) {
var buffer bytes.Buffer

View file

@ -13,18 +13,21 @@ import (
"github.com/remogatto/prettytest"
)
type testSuite struct {
var testdataDir = "./testdata"
type quizTestSuite struct {
prettytest.Suite
}
func TestRunner(t *testing.T) {
prettytest.Run(
t,
new(testSuite),
new(quizTestSuite),
new(collectionTestSuite),
)
}
func (t *testSuite) TestQuizFromMarkdown() {
func (t *quizTestSuite) TestQuizFromMarkdown() {
markdown := `Question text (1).
Question text (2).
@ -55,8 +58,8 @@ Question text with #tag1 #tag2 (3).
}
}
func (t *testSuite) TestReadAllQuizzes() {
store, err := NewFileProboCollectorStore("./testdata/quizzes")
func (t *quizTestSuite) TestReadAllQuizzes() {
store, err := NewFileProboCollectorStore("./testdata/")
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
if !t.Failed() {
@ -75,7 +78,7 @@ func (t *testSuite) TestReadAllQuizzes() {
}
func (t *testSuite) TestMarkdownFromQuiz() {
func (t *quizTestSuite) TestMarkdownFromQuiz() {
store := memory.NewMemoryProboCollectorStore(sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn))
quiz, err := store.CreateQuiz(
&client.CreateUpdateQuizRequest{
@ -102,9 +105,8 @@ func (t *testSuite) TestMarkdownFromQuiz() {
}
}
func (t *testSuite) TestCreateQuiz() {
dirname := "./testdata/quizzes"
store, err := NewFileProboCollectorStore(dirname)
func (t *quizTestSuite) TestCreateQuiz() {
store, err := NewFileProboCollectorStore(testdataDir)
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
@ -127,7 +129,7 @@ func (t *testSuite) TestCreateQuiz() {
t.Nil(err, fmt.Sprintf("An error was raised when saving the quiz on disk: %v", err))
if !t.Failed() {
path, err := store.GetPath(quiz)
path, err := store.GetQuizPath(quiz)
t.Nil(err, "GetPath should not raise an error.")
if !t.Failed() {
@ -151,9 +153,8 @@ func (t *testSuite) TestCreateQuiz() {
}
}
func (t *testSuite) TestDeleteQuiz() {
dirname := "./testdata/quizzes"
store, err := NewFileProboCollectorStore(dirname)
func (t *quizTestSuite) TestDeleteQuiz() {
store, err := NewFileProboCollectorStore(testdataDir)
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
if !t.Failed() {
@ -171,7 +172,7 @@ func (t *testSuite) TestDeleteQuiz() {
t.Nil(err, "The quiz to be deleted should be created without issue")
path, err := store.GetPath(quiz)
path, err := store.GetQuizPath(quiz)
t.True(path != "", "Quiz path should be obtained without errors")
if !t.Failed() {
@ -184,9 +185,8 @@ func (t *testSuite) TestDeleteQuiz() {
}
}
func (t *testSuite) TestUpdateQuiz() {
dirname := "./testdata/quizzes"
store, err := NewFileProboCollectorStore(dirname)
func (t *quizTestSuite) TestUpdateQuiz() {
store, err := NewFileProboCollectorStore(testdataDir)
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
if !t.Failed() {
@ -225,7 +225,7 @@ func (t *testSuite) TestUpdateQuiz() {
t.True(len(updatedQuiz.Tags) == 1, "Length of tags array should be 1")
if !t.Failed() {
path, err := store.GetPath(updatedQuiz)
path, err := store.GetQuizPath(updatedQuiz)
if !t.Failed() {
t.Nil(err, "GetPath should not raise an error.")
@ -246,11 +246,9 @@ func (t *testSuite) TestUpdateQuiz() {
}
func (t *testSuite) TestReadMetaHeaderFromFile() {
dirname := "./testdata/quizzes"
store, err := NewFileProboCollectorStore(dirname)
func (t *quizTestSuite) TestReadMetaHeaderFromFile() {
store, err := NewFileProboCollectorStore(testdataDir)
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))
meta, err := store.ReadMetaHeaderFromFile("quiz_4.md")
t.True(err == nil, fmt.Sprintf("An error occurred: %v", err))
if !t.Failed() {
@ -259,9 +257,8 @@ func (t *testSuite) TestReadMetaHeaderFromFile() {
}
}
func (t *testSuite) TestWriteMetaHeaderToFile() {
dirname := "./testdata/quizzes"
store, err := NewFileProboCollectorStore(dirname)
func (t *quizTestSuite) TestWriteMetaHeaderToFile() {
store, err := NewFileProboCollectorStore(testdataDir)
t.True(err == nil, fmt.Sprintf("A file store should be initialized without problems but an error occurred: %v", err))

View file

@ -1,3 +1,7 @@
---
id: f7034ebc-d62d-43eb-a6cf-57f4886c3a7c
created_at: !!timestamp 2023-10-07T11:38:32.049804383+02:00
---
This quiz is initially without metadata.
* Answer 1

View file

@ -1,6 +1,7 @@
package memory
import (
"errors"
"fmt"
"strings"
"sync"
@ -12,8 +13,8 @@ import (
)
type MemoryProboCollectorStore struct {
quizzes map[string]*models.Quiz
quizzes map[string]*models.Quiz
collections map[string]*models.Collection
questionsHashes map[string]*models.Question
answersHashes map[string]*models.Answer
quizzesHashes map[string]*models.Quiz
@ -34,6 +35,7 @@ func NewMemoryProboCollectorStore(hasher hasher.Hasher) *MemoryProboCollectorSto
s.quizzesHashes = make(map[string]*models.Quiz)
s.quizzes = make(map[string]*models.Quiz)
s.collections = make(map[string]*models.Collection)
return s
}
@ -62,6 +64,18 @@ func (s *MemoryProboCollectorStore) getQuizFromID(id string) *models.Quiz {
return nil
}
func (s *MemoryProboCollectorStore) getCollectionFromID(id string) *models.Collection {
s.lock.RLock()
defer s.lock.RUnlock()
collection, ok := s.collections[id]
if ok {
return collection
}
return nil
}
func (s *MemoryProboCollectorStore) getQuestionFromHash(hash string) *models.Question {
s.lock.RLock()
defer s.lock.RUnlock()
@ -185,6 +199,9 @@ func (s *MemoryProboCollectorStore) parseTextForTags(text string, tags *[]*model
}
func (s *MemoryProboCollectorStore) createOrUpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, bool, error) {
if r.Quiz == nil {
return nil, false, errors.New("A request was made passing a nil quiz object")
}
hashes := s.hasher.QuizHashes(r.Quiz)
quizHash := hashes[len(hashes)-1]
@ -260,3 +277,74 @@ func (s *MemoryProboCollectorStore) UpdateQuiz(r *client.CreateUpdateQuizRequest
func (s *MemoryProboCollectorStore) DeleteQuiz(id string) (*models.Quiz, error) {
return s.deleteQuiz(id)
}
func (s *MemoryProboCollectorStore) CreateCollection(r *client.CreateUpdateCollectionRequest) (*models.Collection, error) {
q, _, err := s.createOrUpdateCollection(r, "")
return q, err
}
func (s *MemoryProboCollectorStore) UpdateCollection(r *client.CreateUpdateCollectionRequest, id string) (*models.Collection, bool, error) {
return s.createOrUpdateCollection(r, id)
}
func (s *MemoryProboCollectorStore) ReadCollectionByID(id string) (*models.Collection, error) {
collection := s.getCollectionFromID(id)
if collection == nil {
return nil, fmt.Errorf("Collection ID %v not found in the store", collection.ID)
}
return collection, nil
}
func (s *MemoryProboCollectorStore) createOrUpdateCollection(r *client.CreateUpdateCollectionRequest, id string) (*models.Collection, bool, error) {
var collection *models.Collection
if r.Collection == nil {
return nil, false, errors.New("A request was made passing a nil collection object")
}
if id != "" { // we're updating a collection
collection = s.getCollectionFromID(id)
if collection == nil { // Quiz is not present in the store
return nil, false, fmt.Errorf("Collection ID %v doesn't exist in the store!", id)
}
} else {
id = uuid.New().String()
collection = new(models.Collection)
}
collection.Name = r.Collection.Name
collection.Query = r.Collection.Query
collection.IDs = s.query(collection.Query)
return s.createCollectionFromID(id, collection), true, nil
}
func (s *MemoryProboCollectorStore) query(query string) []string {
s.lock.Lock()
defer s.lock.Unlock()
result := make([]string, 0)
for id, quiz := range s.quizzes {
for _, tag := range quiz.Tags {
if query == tag.Name {
result = append(result, id)
break
}
}
}
return result
}
func (s *MemoryProboCollectorStore) createCollectionFromID(id string, collection *models.Collection) *models.Collection {
s.lock.Lock()
defer s.lock.Unlock()
collection.ID = id
s.collections[id] = collection
return collection
}

View file

@ -139,3 +139,62 @@ func (t *testSuite) TestDeleteQuiz() {
_, err = store.ReadQuizByHash(quiz.Hash)
t.True(err != nil, "Reading a non existent quiz should return an error")
}
func (t *testSuite) TestUpdateCollection() {
store := NewMemoryProboCollectorStore(
sha256.NewDefault256Hasher(sha256.DefaultSHA256HashingFn),
)
quiz_1, _ := store.CreateQuiz(
&client.CreateUpdateQuizRequest{
Quiz: &client.Quiz{
Question: &client.Question{Text: "Question text with #tag1."},
Answers: []*client.Answer{
{Text: "Answer 1", Correct: true},
{Text: "Answer 2", Correct: false},
{Text: "Answer 3", Correct: false},
{Text: "Answer 4", Correct: false},
},
},
})
quiz_2, _ := store.CreateQuiz(
&client.CreateUpdateQuizRequest{
Quiz: &client.Quiz{
Question: &client.Question{Text: "Another question text with #tag1."},
Answers: []*client.Answer{
{Text: "Answer 1", Correct: true},
{Text: "Answer 2", Correct: false},
{Text: "Answer 3", Correct: false},
{Text: "Answer 4", Correct: false},
},
},
})
collection, _ := store.CreateCollection(
&client.CreateUpdateCollectionRequest{
Collection: &client.Collection{
Name: "MyCollection",
},
})
updatedCollection, updated, err := store.UpdateCollection(
&client.CreateUpdateCollectionRequest{
Collection: &client.Collection{
Name: "MyUpdatedCollection",
Query: "#tag1",
},
}, collection.ID)
t.Nil(err, fmt.Sprintf("The update returned an error: %v", err))
if !t.Failed() {
t.True(updated)
t.Equal("MyUpdatedCollection", updatedCollection.Name)
t.True(len(updatedCollection.IDs) == 2)
if !t.Failed() {
t.Equal(quiz_1.ID, updatedCollection.IDs[0])
t.Equal(quiz_2.ID, updatedCollection.IDs[1])
}
}
}

View file

@ -7,10 +7,14 @@ import (
type ProboCollectorStore interface {
ReadAllQuizzes() ([]*models.Quiz, error)
ReadQuizByHash(hash string) (*models.Quiz, error)
CreateQuiz(r *client.CreateUpdateQuizRequest) (*models.Quiz, error)
UpdateQuiz(r *client.CreateUpdateQuizRequest, id string) (*models.Quiz, error)
DeleteQuiz(r *client.DeleteQuizRequest) (*models.Quiz, error)
ReadAllCollections() ([]*models.Collection, error)
ReadCollectionByID(id string) (*models.Collection, error)
CreateCollection(r *client.CreateUpdateCollectionRequest) (*models.Collection, error)
UpdateCollection(r *client.CreateUpdateCollectionRequest, id string) (*models.Collection, error)
DeleteCollection(r *client.DeleteCollectionRequest) (*models.Collection, error)
}