Add stub fs module with maildir utils

This commit is contained in:
Blallo 2021-01-14 18:08:04 +01:00
parent 483f84a443
commit fa972455b3
No known key found for this signature in database
GPG key ID: 0CBE577C9B72DC3F
3 changed files with 222 additions and 0 deletions

62
fs/clock.go Normal file
View file

@ -0,0 +1,62 @@
package fs
import (
"time"
)
var now time.Time
func init() {
now = time.Now()
}
type ticker interface {
getC() <-chan time.Time
}
type clock interface {
Now() time.Time
Ticker() ticker
}
type realTicker time.Ticker
func (rt realTicker) getC() <-chan time.Time {
return rt.C
}
type realClock struct{}
func (rc realClock) Now() time.Time {
return time.Now()
}
func (rc realClock) Ticker() ticker {
ticker := time.NewTicker(time.Second)
return realTicker(*ticker)
}
type mockClock struct{}
func (mc mockClock) Now() time.Time {
return now
}
func (mc mockClock) Ticker() ticker {
return newMockTicker()
}
type mockTicker struct {
c <-chan time.Time
}
func (mc mockTicker) getC() <-chan time.Time {
return mc.c
}
func newMockTicker() mockTicker {
c := make(<-chan time.Time)
return mockTicker{
c: c,
}
}

125
fs/maildir.go Normal file
View file

@ -0,0 +1,125 @@
package fs
import (
"fmt"
"os"
"strings"
"time"
)
type Flag string
func cat(f []Flag) string {
var list []string
for _, el := range f {
list = append(list, string(el))
}
return strings.Join(list, "")
}
const (
Seen Flag = "S"
Answered = "R"
Flagged = "F"
Deleted = "T"
Draft = "D"
)
// MailFile holds the information needed to format the name of the file
// containing a single email. The format is:
// `<%d_%d.%d.%s>,U=<%d>,FMD5=<%s>:2,<FLAGS>`
// (logical groups being enclosed by angle brackets) where:
// - `<%d_%d.%d.%s>` is the concatenation of:
// * system unix timestamp of arrival time of the message
// * a progressive number to distinguish messages arrived at once
// * pid of the current process
// * hostname of the local machine
// - `,U=<%d>` holds the UID of the message as decided by the server
// - `,FMD5=<%s>:2` holds the md5sum of the name of the current mailbox
// - `,<FLAGS>` carries the flags active on the message
type MailFile struct {
timestamp time.Time
progressive int
pid int
hostname string
uid int
md5 string
flags []Flag
}
func (m *MailFile) SetUid(uid int) {
m.uid = uid
}
func (m *MailFile) SetMd5(md5 string) {
m.md5 = md5
}
func (m *MailFile) SetFlags(flags []Flag) {
m.flags = flags
}
func (m *MailFile) String() string {
return fmt.Sprintf(
"%d_%d.%d.%s,U=%d,FMD5=%s:2,%s",
m.timestamp.Unix(),
m.progressive,
m.pid,
m.hostname,
m.uid,
m.md5,
cat(m.flags),
)
}
type MailFileRequest struct {
respCh chan MailFile
}
func NewMailFileRequest() MailFileRequest {
ch := make(chan MailFile)
return MailFileRequest{respCh: ch}
}
func (r MailFileRequest) Response() MailFile {
return <-r.respCh
}
func NewOracle() chan MailFileRequest {
r := realClock{}
return newOracle(r)
}
func newOracle(c clock) chan MailFileRequest {
reqCh := make(chan MailFileRequest, 10)
go spawnOracle(reqCh, c)
return reqCh
}
func spawnOracle(reqCh <-chan MailFileRequest, c clock) {
count := 0
C := c.Ticker().getC()
pid := os.Getpid()
hostname, err := os.Hostname()
if err != nil {
hostname = "MISSING"
}
for {
select {
case <-C:
count = 0
case req := <-reqCh:
req.respCh <- MailFile{
timestamp: c.Now(),
progressive: count,
pid: pid,
hostname: hostname,
}
count += 1
}
}
}
type MailDir struct {
basePath string
}

35
fs/maildir_test.go Normal file
View file

@ -0,0 +1,35 @@
package fs
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestMailFileString(t *testing.T) {
var message_nums = []int{0, 1, 2, 3, 4}
var results []MailFile
clock := mockClock{}
oracle := newOracle(clock)
for range message_nums {
req := NewMailFileRequest()
oracle <- req
results = append(results, req.Response())
}
for i := range message_nums[1:] {
timestamp_c := results[0].timestamp != results[i].timestamp
pid_c := results[0].pid != results[i].pid
hostname_c := results[0].hostname != results[i].hostname
if timestamp_c || pid_c || hostname_c {
t.Logf("timestamp_c: %+v\n", timestamp_c)
t.Logf("pid_c: %+v\n", pid_c)
t.Logf("hostname_c: %+v\n", hostname_c)
t.Errorf("Mismatching timestamps, %+v\n", cmp.Diff(results[0], results[i], cmp.AllowUnexported(MailFile{})))
}
if results[i].progressive != i {
t.Errorf("Unexpected progressive -> have: %d | expect: %d\n", results[i].progressive, i)
}
}
}