diff --git a/generate.go b/generate.go index 145e9a02..d2ac6b79 100644 --- a/generate.go +++ b/generate.go @@ -3,3 +3,4 @@ package radio //go:generate go generate ./rpc/generate.go //go:generate moq -out mocks/radio.gen.go -pkg mocks . StorageService StorageTx TrackStorage SubmissionStorage UserStorage //go:generate moq -out mocks/templates.gen.go -pkg mocks ./templates/ Executor +//go:generate moq -out mocks/util.gen.go -pkg mocks ./mocks/ FS File FileInfo diff --git a/go.mod b/go.mod index 1e1153b5..268ece3e 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/XSAM/otelsql v0.27.0 github.com/alexedwards/scs/v2 v2.7.0 github.com/cenkalti/backoff v2.2.1+incompatible + github.com/davecgh/go-spew v1.1.1 github.com/go-sql-driver/mysql v1.7.1 github.com/golang-migrate/migrate/v4 v4.17.0 github.com/google/subcommands v1.2.0 @@ -33,6 +34,7 @@ require ( golang.org/x/crypto v0.18.0 golang.org/x/exp v0.0.0-20240119083558-1b970713d09a golang.org/x/text v0.14.0 + golang.org/x/tools v0.17.0 google.golang.org/grpc v1.61.0 ) @@ -45,7 +47,6 @@ require ( github.com/containerd/containerd v1.7.11 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -85,7 +86,6 @@ require ( golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/sys v0.16.0 // indirect - golang.org/x/tools v0.17.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/mocks/util.gen.go b/mocks/util.gen.go new file mode 100644 index 00000000..3aba8ce1 --- /dev/null +++ b/mocks/util.gen.go @@ -0,0 +1,636 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package mocks + +import ( + "io/fs" + "sync" + "time" +) + +// Ensure, that FSMock does implement FS. +// If this is not the case, regenerate this file with moq. +var _ FS = &FSMock{} + +// FSMock is a mock implementation of FS. +// +// func TestSomethingThatUsesFS(t *testing.T) { +// +// // make and configure a mocked FS +// mockedFS := &FSMock{ +// GlobFunc: func(pattern string) ([]string, error) { +// panic("mock out the Glob method") +// }, +// OpenFunc: func(name string) (fs.File, error) { +// panic("mock out the Open method") +// }, +// ReadFileFunc: func(name string) ([]byte, error) { +// panic("mock out the ReadFile method") +// }, +// StatFunc: func(name string) (fs.FileInfo, error) { +// panic("mock out the Stat method") +// }, +// SubFunc: func(dir string) (fs.FS, error) { +// panic("mock out the Sub method") +// }, +// } +// +// // use mockedFS in code that requires FS +// // and then make assertions. +// +// } +type FSMock struct { + // GlobFunc mocks the Glob method. + GlobFunc func(pattern string) ([]string, error) + + // OpenFunc mocks the Open method. + OpenFunc func(name string) (fs.File, error) + + // ReadFileFunc mocks the ReadFile method. + ReadFileFunc func(name string) ([]byte, error) + + // StatFunc mocks the Stat method. + StatFunc func(name string) (fs.FileInfo, error) + + // SubFunc mocks the Sub method. + SubFunc func(dir string) (fs.FS, error) + + // calls tracks calls to the methods. + calls struct { + // Glob holds details about calls to the Glob method. + Glob []struct { + // Pattern is the pattern argument value. + Pattern string + } + // Open holds details about calls to the Open method. + Open []struct { + // Name is the name argument value. + Name string + } + // ReadFile holds details about calls to the ReadFile method. + ReadFile []struct { + // Name is the name argument value. + Name string + } + // Stat holds details about calls to the Stat method. + Stat []struct { + // Name is the name argument value. + Name string + } + // Sub holds details about calls to the Sub method. + Sub []struct { + // Dir is the dir argument value. + Dir string + } + } + lockGlob sync.RWMutex + lockOpen sync.RWMutex + lockReadFile sync.RWMutex + lockStat sync.RWMutex + lockSub sync.RWMutex +} + +// Glob calls GlobFunc. +func (mock *FSMock) Glob(pattern string) ([]string, error) { + if mock.GlobFunc == nil { + panic("FSMock.GlobFunc: method is nil but FS.Glob was just called") + } + callInfo := struct { + Pattern string + }{ + Pattern: pattern, + } + mock.lockGlob.Lock() + mock.calls.Glob = append(mock.calls.Glob, callInfo) + mock.lockGlob.Unlock() + return mock.GlobFunc(pattern) +} + +// GlobCalls gets all the calls that were made to Glob. +// Check the length with: +// +// len(mockedFS.GlobCalls()) +func (mock *FSMock) GlobCalls() []struct { + Pattern string +} { + var calls []struct { + Pattern string + } + mock.lockGlob.RLock() + calls = mock.calls.Glob + mock.lockGlob.RUnlock() + return calls +} + +// Open calls OpenFunc. +func (mock *FSMock) Open(name string) (fs.File, error) { + if mock.OpenFunc == nil { + panic("FSMock.OpenFunc: method is nil but FS.Open was just called") + } + callInfo := struct { + Name string + }{ + Name: name, + } + mock.lockOpen.Lock() + mock.calls.Open = append(mock.calls.Open, callInfo) + mock.lockOpen.Unlock() + return mock.OpenFunc(name) +} + +// OpenCalls gets all the calls that were made to Open. +// Check the length with: +// +// len(mockedFS.OpenCalls()) +func (mock *FSMock) OpenCalls() []struct { + Name string +} { + var calls []struct { + Name string + } + mock.lockOpen.RLock() + calls = mock.calls.Open + mock.lockOpen.RUnlock() + return calls +} + +// ReadFile calls ReadFileFunc. +func (mock *FSMock) ReadFile(name string) ([]byte, error) { + if mock.ReadFileFunc == nil { + panic("FSMock.ReadFileFunc: method is nil but FS.ReadFile was just called") + } + callInfo := struct { + Name string + }{ + Name: name, + } + mock.lockReadFile.Lock() + mock.calls.ReadFile = append(mock.calls.ReadFile, callInfo) + mock.lockReadFile.Unlock() + return mock.ReadFileFunc(name) +} + +// ReadFileCalls gets all the calls that were made to ReadFile. +// Check the length with: +// +// len(mockedFS.ReadFileCalls()) +func (mock *FSMock) ReadFileCalls() []struct { + Name string +} { + var calls []struct { + Name string + } + mock.lockReadFile.RLock() + calls = mock.calls.ReadFile + mock.lockReadFile.RUnlock() + return calls +} + +// Stat calls StatFunc. +func (mock *FSMock) Stat(name string) (fs.FileInfo, error) { + if mock.StatFunc == nil { + panic("FSMock.StatFunc: method is nil but FS.Stat was just called") + } + callInfo := struct { + Name string + }{ + Name: name, + } + mock.lockStat.Lock() + mock.calls.Stat = append(mock.calls.Stat, callInfo) + mock.lockStat.Unlock() + return mock.StatFunc(name) +} + +// StatCalls gets all the calls that were made to Stat. +// Check the length with: +// +// len(mockedFS.StatCalls()) +func (mock *FSMock) StatCalls() []struct { + Name string +} { + var calls []struct { + Name string + } + mock.lockStat.RLock() + calls = mock.calls.Stat + mock.lockStat.RUnlock() + return calls +} + +// Sub calls SubFunc. +func (mock *FSMock) Sub(dir string) (fs.FS, error) { + if mock.SubFunc == nil { + panic("FSMock.SubFunc: method is nil but FS.Sub was just called") + } + callInfo := struct { + Dir string + }{ + Dir: dir, + } + mock.lockSub.Lock() + mock.calls.Sub = append(mock.calls.Sub, callInfo) + mock.lockSub.Unlock() + return mock.SubFunc(dir) +} + +// SubCalls gets all the calls that were made to Sub. +// Check the length with: +// +// len(mockedFS.SubCalls()) +func (mock *FSMock) SubCalls() []struct { + Dir string +} { + var calls []struct { + Dir string + } + mock.lockSub.RLock() + calls = mock.calls.Sub + mock.lockSub.RUnlock() + return calls +} + +// Ensure, that FileMock does implement File. +// If this is not the case, regenerate this file with moq. +var _ File = &FileMock{} + +// FileMock is a mock implementation of File. +// +// func TestSomethingThatUsesFile(t *testing.T) { +// +// // make and configure a mocked File +// mockedFile := &FileMock{ +// CloseFunc: func() error { +// panic("mock out the Close method") +// }, +// ReadFunc: func(bytes []byte) (int, error) { +// panic("mock out the Read method") +// }, +// StatFunc: func() (fs.FileInfo, error) { +// panic("mock out the Stat method") +// }, +// } +// +// // use mockedFile in code that requires File +// // and then make assertions. +// +// } +type FileMock struct { + // CloseFunc mocks the Close method. + CloseFunc func() error + + // ReadFunc mocks the Read method. + ReadFunc func(bytes []byte) (int, error) + + // StatFunc mocks the Stat method. + StatFunc func() (fs.FileInfo, error) + + // calls tracks calls to the methods. + calls struct { + // Close holds details about calls to the Close method. + Close []struct { + } + // Read holds details about calls to the Read method. + Read []struct { + // Bytes is the bytes argument value. + Bytes []byte + } + // Stat holds details about calls to the Stat method. + Stat []struct { + } + } + lockClose sync.RWMutex + lockRead sync.RWMutex + lockStat sync.RWMutex +} + +// Close calls CloseFunc. +func (mock *FileMock) Close() error { + if mock.CloseFunc == nil { + panic("FileMock.CloseFunc: method is nil but File.Close was just called") + } + callInfo := struct { + }{} + mock.lockClose.Lock() + mock.calls.Close = append(mock.calls.Close, callInfo) + mock.lockClose.Unlock() + return mock.CloseFunc() +} + +// CloseCalls gets all the calls that were made to Close. +// Check the length with: +// +// len(mockedFile.CloseCalls()) +func (mock *FileMock) CloseCalls() []struct { +} { + var calls []struct { + } + mock.lockClose.RLock() + calls = mock.calls.Close + mock.lockClose.RUnlock() + return calls +} + +// Read calls ReadFunc. +func (mock *FileMock) Read(bytes []byte) (int, error) { + if mock.ReadFunc == nil { + panic("FileMock.ReadFunc: method is nil but File.Read was just called") + } + callInfo := struct { + Bytes []byte + }{ + Bytes: bytes, + } + mock.lockRead.Lock() + mock.calls.Read = append(mock.calls.Read, callInfo) + mock.lockRead.Unlock() + return mock.ReadFunc(bytes) +} + +// ReadCalls gets all the calls that were made to Read. +// Check the length with: +// +// len(mockedFile.ReadCalls()) +func (mock *FileMock) ReadCalls() []struct { + Bytes []byte +} { + var calls []struct { + Bytes []byte + } + mock.lockRead.RLock() + calls = mock.calls.Read + mock.lockRead.RUnlock() + return calls +} + +// Stat calls StatFunc. +func (mock *FileMock) Stat() (fs.FileInfo, error) { + if mock.StatFunc == nil { + panic("FileMock.StatFunc: method is nil but File.Stat was just called") + } + callInfo := struct { + }{} + mock.lockStat.Lock() + mock.calls.Stat = append(mock.calls.Stat, callInfo) + mock.lockStat.Unlock() + return mock.StatFunc() +} + +// StatCalls gets all the calls that were made to Stat. +// Check the length with: +// +// len(mockedFile.StatCalls()) +func (mock *FileMock) StatCalls() []struct { +} { + var calls []struct { + } + mock.lockStat.RLock() + calls = mock.calls.Stat + mock.lockStat.RUnlock() + return calls +} + +// Ensure, that FileInfoMock does implement FileInfo. +// If this is not the case, regenerate this file with moq. +var _ FileInfo = &FileInfoMock{} + +// FileInfoMock is a mock implementation of FileInfo. +// +// func TestSomethingThatUsesFileInfo(t *testing.T) { +// +// // make and configure a mocked FileInfo +// mockedFileInfo := &FileInfoMock{ +// IsDirFunc: func() bool { +// panic("mock out the IsDir method") +// }, +// ModTimeFunc: func() time.Time { +// panic("mock out the ModTime method") +// }, +// ModeFunc: func() fs.FileMode { +// panic("mock out the Mode method") +// }, +// NameFunc: func() string { +// panic("mock out the Name method") +// }, +// SizeFunc: func() int64 { +// panic("mock out the Size method") +// }, +// SysFunc: func() any { +// panic("mock out the Sys method") +// }, +// } +// +// // use mockedFileInfo in code that requires FileInfo +// // and then make assertions. +// +// } +type FileInfoMock struct { + // IsDirFunc mocks the IsDir method. + IsDirFunc func() bool + + // ModTimeFunc mocks the ModTime method. + ModTimeFunc func() time.Time + + // ModeFunc mocks the Mode method. + ModeFunc func() fs.FileMode + + // NameFunc mocks the Name method. + NameFunc func() string + + // SizeFunc mocks the Size method. + SizeFunc func() int64 + + // SysFunc mocks the Sys method. + SysFunc func() any + + // calls tracks calls to the methods. + calls struct { + // IsDir holds details about calls to the IsDir method. + IsDir []struct { + } + // ModTime holds details about calls to the ModTime method. + ModTime []struct { + } + // Mode holds details about calls to the Mode method. + Mode []struct { + } + // Name holds details about calls to the Name method. + Name []struct { + } + // Size holds details about calls to the Size method. + Size []struct { + } + // Sys holds details about calls to the Sys method. + Sys []struct { + } + } + lockIsDir sync.RWMutex + lockModTime sync.RWMutex + lockMode sync.RWMutex + lockName sync.RWMutex + lockSize sync.RWMutex + lockSys sync.RWMutex +} + +// IsDir calls IsDirFunc. +func (mock *FileInfoMock) IsDir() bool { + if mock.IsDirFunc == nil { + panic("FileInfoMock.IsDirFunc: method is nil but FileInfo.IsDir was just called") + } + callInfo := struct { + }{} + mock.lockIsDir.Lock() + mock.calls.IsDir = append(mock.calls.IsDir, callInfo) + mock.lockIsDir.Unlock() + return mock.IsDirFunc() +} + +// IsDirCalls gets all the calls that were made to IsDir. +// Check the length with: +// +// len(mockedFileInfo.IsDirCalls()) +func (mock *FileInfoMock) IsDirCalls() []struct { +} { + var calls []struct { + } + mock.lockIsDir.RLock() + calls = mock.calls.IsDir + mock.lockIsDir.RUnlock() + return calls +} + +// ModTime calls ModTimeFunc. +func (mock *FileInfoMock) ModTime() time.Time { + if mock.ModTimeFunc == nil { + panic("FileInfoMock.ModTimeFunc: method is nil but FileInfo.ModTime was just called") + } + callInfo := struct { + }{} + mock.lockModTime.Lock() + mock.calls.ModTime = append(mock.calls.ModTime, callInfo) + mock.lockModTime.Unlock() + return mock.ModTimeFunc() +} + +// ModTimeCalls gets all the calls that were made to ModTime. +// Check the length with: +// +// len(mockedFileInfo.ModTimeCalls()) +func (mock *FileInfoMock) ModTimeCalls() []struct { +} { + var calls []struct { + } + mock.lockModTime.RLock() + calls = mock.calls.ModTime + mock.lockModTime.RUnlock() + return calls +} + +// Mode calls ModeFunc. +func (mock *FileInfoMock) Mode() fs.FileMode { + if mock.ModeFunc == nil { + panic("FileInfoMock.ModeFunc: method is nil but FileInfo.Mode was just called") + } + callInfo := struct { + }{} + mock.lockMode.Lock() + mock.calls.Mode = append(mock.calls.Mode, callInfo) + mock.lockMode.Unlock() + return mock.ModeFunc() +} + +// ModeCalls gets all the calls that were made to Mode. +// Check the length with: +// +// len(mockedFileInfo.ModeCalls()) +func (mock *FileInfoMock) ModeCalls() []struct { +} { + var calls []struct { + } + mock.lockMode.RLock() + calls = mock.calls.Mode + mock.lockMode.RUnlock() + return calls +} + +// Name calls NameFunc. +func (mock *FileInfoMock) Name() string { + if mock.NameFunc == nil { + panic("FileInfoMock.NameFunc: method is nil but FileInfo.Name was just called") + } + callInfo := struct { + }{} + mock.lockName.Lock() + mock.calls.Name = append(mock.calls.Name, callInfo) + mock.lockName.Unlock() + return mock.NameFunc() +} + +// NameCalls gets all the calls that were made to Name. +// Check the length with: +// +// len(mockedFileInfo.NameCalls()) +func (mock *FileInfoMock) NameCalls() []struct { +} { + var calls []struct { + } + mock.lockName.RLock() + calls = mock.calls.Name + mock.lockName.RUnlock() + return calls +} + +// Size calls SizeFunc. +func (mock *FileInfoMock) Size() int64 { + if mock.SizeFunc == nil { + panic("FileInfoMock.SizeFunc: method is nil but FileInfo.Size was just called") + } + callInfo := struct { + }{} + mock.lockSize.Lock() + mock.calls.Size = append(mock.calls.Size, callInfo) + mock.lockSize.Unlock() + return mock.SizeFunc() +} + +// SizeCalls gets all the calls that were made to Size. +// Check the length with: +// +// len(mockedFileInfo.SizeCalls()) +func (mock *FileInfoMock) SizeCalls() []struct { +} { + var calls []struct { + } + mock.lockSize.RLock() + calls = mock.calls.Size + mock.lockSize.RUnlock() + return calls +} + +// Sys calls SysFunc. +func (mock *FileInfoMock) Sys() any { + if mock.SysFunc == nil { + panic("FileInfoMock.SysFunc: method is nil but FileInfo.Sys was just called") + } + callInfo := struct { + }{} + mock.lockSys.Lock() + mock.calls.Sys = append(mock.calls.Sys, callInfo) + mock.lockSys.Unlock() + return mock.SysFunc() +} + +// SysCalls gets all the calls that were made to Sys. +// Check the length with: +// +// len(mockedFileInfo.SysCalls()) +func (mock *FileInfoMock) SysCalls() []struct { +} { + var calls []struct { + } + mock.lockSys.RLock() + calls = mock.calls.Sys + mock.lockSys.RUnlock() + return calls +} diff --git a/mocks/util.go b/mocks/util.go new file mode 100644 index 00000000..cb9aacc5 --- /dev/null +++ b/mocks/util.go @@ -0,0 +1,13 @@ +package mocks + +import "io/fs" + +type FS interface { + fs.GlobFS + fs.ReadFileFS + fs.StatFS + fs.SubFS +} + +type File = fs.File +type FileInfo = fs.FileInfo diff --git a/rpc/radio.pb.go b/rpc/radio.pb.go index c3e3a0dc..b4e938e8 100644 --- a/rpc/radio.pb.go +++ b/rpc/radio.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v3.15.8 +// protoc-gen-go v1.28.1 +// protoc v3.21.12 // source: radio.proto package rpc diff --git a/rpc/radio_grpc.pb.go b/rpc/radio_grpc.pb.go index bdbfe837..4f1c9393 100644 --- a/rpc/radio_grpc.pb.go +++ b/rpc/radio_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v3.15.8 +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.21.12 // source: radio.proto package rpc @@ -20,18 +20,6 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 -const ( - Manager_Status_FullMethodName = "/radio.Manager/Status" - Manager_CurrentSong_FullMethodName = "/radio.Manager/CurrentSong" - Manager_UpdateSong_FullMethodName = "/radio.Manager/UpdateSong" - Manager_CurrentThread_FullMethodName = "/radio.Manager/CurrentThread" - Manager_UpdateThread_FullMethodName = "/radio.Manager/UpdateThread" - Manager_CurrentUser_FullMethodName = "/radio.Manager/CurrentUser" - Manager_UpdateUser_FullMethodName = "/radio.Manager/UpdateUser" - Manager_CurrentListenerCount_FullMethodName = "/radio.Manager/CurrentListenerCount" - Manager_UpdateListenerCount_FullMethodName = "/radio.Manager/UpdateListenerCount" -) - // ManagerClient is the client API for Manager service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -57,7 +45,7 @@ func NewManagerClient(cc grpc.ClientConnInterface) ManagerClient { func (c *managerClient) Status(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*StatusResponse, error) { out := new(StatusResponse) - err := c.cc.Invoke(ctx, Manager_Status_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Manager/Status", in, out, opts...) if err != nil { return nil, err } @@ -65,7 +53,7 @@ func (c *managerClient) Status(ctx context.Context, in *emptypb.Empty, opts ...g } func (c *managerClient) CurrentSong(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (Manager_CurrentSongClient, error) { - stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[0], Manager_CurrentSong_FullMethodName, opts...) + stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[0], "/radio.Manager/CurrentSong", opts...) if err != nil { return nil, err } @@ -98,7 +86,7 @@ func (x *managerCurrentSongClient) Recv() (*SongUpdate, error) { func (c *managerClient) UpdateSong(ctx context.Context, in *SongUpdate, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Manager_UpdateSong_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Manager/UpdateSong", in, out, opts...) if err != nil { return nil, err } @@ -106,7 +94,7 @@ func (c *managerClient) UpdateSong(ctx context.Context, in *SongUpdate, opts ... } func (c *managerClient) CurrentThread(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (Manager_CurrentThreadClient, error) { - stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[1], Manager_CurrentThread_FullMethodName, opts...) + stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[1], "/radio.Manager/CurrentThread", opts...) if err != nil { return nil, err } @@ -139,7 +127,7 @@ func (x *managerCurrentThreadClient) Recv() (*wrapperspb.StringValue, error) { func (c *managerClient) UpdateThread(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Manager_UpdateThread_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Manager/UpdateThread", in, out, opts...) if err != nil { return nil, err } @@ -147,7 +135,7 @@ func (c *managerClient) UpdateThread(ctx context.Context, in *wrapperspb.StringV } func (c *managerClient) CurrentUser(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (Manager_CurrentUserClient, error) { - stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[2], Manager_CurrentUser_FullMethodName, opts...) + stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[2], "/radio.Manager/CurrentUser", opts...) if err != nil { return nil, err } @@ -180,7 +168,7 @@ func (x *managerCurrentUserClient) Recv() (*User, error) { func (c *managerClient) UpdateUser(ctx context.Context, in *User, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Manager_UpdateUser_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Manager/UpdateUser", in, out, opts...) if err != nil { return nil, err } @@ -188,7 +176,7 @@ func (c *managerClient) UpdateUser(ctx context.Context, in *User, opts ...grpc.C } func (c *managerClient) CurrentListenerCount(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (Manager_CurrentListenerCountClient, error) { - stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[3], Manager_CurrentListenerCount_FullMethodName, opts...) + stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[3], "/radio.Manager/CurrentListenerCount", opts...) if err != nil { return nil, err } @@ -221,7 +209,7 @@ func (x *managerCurrentListenerCountClient) Recv() (*wrapperspb.Int64Value, erro func (c *managerClient) UpdateListenerCount(ctx context.Context, in *wrapperspb.Int64Value, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Manager_UpdateListenerCount_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Manager/UpdateListenerCount", in, out, opts...) if err != nil { return nil, err } @@ -298,7 +286,7 @@ func _Manager_Status_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Manager_Status_FullMethodName, + FullMethod: "/radio.Manager/Status", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ManagerServer).Status(ctx, req.(*emptypb.Empty)) @@ -337,7 +325,7 @@ func _Manager_UpdateSong_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Manager_UpdateSong_FullMethodName, + FullMethod: "/radio.Manager/UpdateSong", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ManagerServer).UpdateSong(ctx, req.(*SongUpdate)) @@ -376,7 +364,7 @@ func _Manager_UpdateThread_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Manager_UpdateThread_FullMethodName, + FullMethod: "/radio.Manager/UpdateThread", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ManagerServer).UpdateThread(ctx, req.(*wrapperspb.StringValue)) @@ -415,7 +403,7 @@ func _Manager_UpdateUser_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Manager_UpdateUser_FullMethodName, + FullMethod: "/radio.Manager/UpdateUser", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ManagerServer).UpdateUser(ctx, req.(*User)) @@ -454,7 +442,7 @@ func _Manager_UpdateListenerCount_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Manager_UpdateListenerCount_FullMethodName, + FullMethod: "/radio.Manager/UpdateListenerCount", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ManagerServer).UpdateListenerCount(ctx, req.(*wrapperspb.Int64Value)) @@ -515,11 +503,6 @@ var Manager_ServiceDesc = grpc.ServiceDesc{ Metadata: "radio.proto", } -const ( - Announcer_AnnounceSong_FullMethodName = "/radio.Announcer/AnnounceSong" - Announcer_AnnounceRequest_FullMethodName = "/radio.Announcer/AnnounceRequest" -) - // AnnouncerClient is the client API for Announcer service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -538,7 +521,7 @@ func NewAnnouncerClient(cc grpc.ClientConnInterface) AnnouncerClient { func (c *announcerClient) AnnounceSong(ctx context.Context, in *SongAnnouncement, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Announcer_AnnounceSong_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Announcer/AnnounceSong", in, out, opts...) if err != nil { return nil, err } @@ -547,7 +530,7 @@ func (c *announcerClient) AnnounceSong(ctx context.Context, in *SongAnnouncement func (c *announcerClient) AnnounceRequest(ctx context.Context, in *SongRequestAnnouncement, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Announcer_AnnounceRequest_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Announcer/AnnounceRequest", in, out, opts...) if err != nil { return nil, err } @@ -596,7 +579,7 @@ func _Announcer_AnnounceSong_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Announcer_AnnounceSong_FullMethodName, + FullMethod: "/radio.Announcer/AnnounceSong", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(AnnouncerServer).AnnounceSong(ctx, req.(*SongAnnouncement)) @@ -614,7 +597,7 @@ func _Announcer_AnnounceRequest_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Announcer_AnnounceRequest_FullMethodName, + FullMethod: "/radio.Announcer/AnnounceRequest", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(AnnouncerServer).AnnounceRequest(ctx, req.(*SongRequestAnnouncement)) @@ -642,14 +625,6 @@ var Announcer_ServiceDesc = grpc.ServiceDesc{ Metadata: "radio.proto", } -const ( - Streamer_Start_FullMethodName = "/radio.Streamer/Start" - Streamer_Stop_FullMethodName = "/radio.Streamer/Stop" - Streamer_RequestSong_FullMethodName = "/radio.Streamer/RequestSong" - Streamer_SetConfig_FullMethodName = "/radio.Streamer/SetConfig" - Streamer_Queue_FullMethodName = "/radio.Streamer/Queue" -) - // StreamerClient is the client API for Streamer service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -677,7 +652,7 @@ func NewStreamerClient(cc grpc.ClientConnInterface) StreamerClient { func (c *streamerClient) Start(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*StreamerResponse, error) { out := new(StreamerResponse) - err := c.cc.Invoke(ctx, Streamer_Start_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Streamer/Start", in, out, opts...) if err != nil { return nil, err } @@ -686,7 +661,7 @@ func (c *streamerClient) Start(ctx context.Context, in *emptypb.Empty, opts ...g func (c *streamerClient) Stop(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*StreamerResponse, error) { out := new(StreamerResponse) - err := c.cc.Invoke(ctx, Streamer_Stop_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Streamer/Stop", in, out, opts...) if err != nil { return nil, err } @@ -695,7 +670,7 @@ func (c *streamerClient) Stop(ctx context.Context, in *wrapperspb.BoolValue, opt func (c *streamerClient) RequestSong(ctx context.Context, in *SongRequest, opts ...grpc.CallOption) (*RequestResponse, error) { out := new(RequestResponse) - err := c.cc.Invoke(ctx, Streamer_RequestSong_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Streamer/RequestSong", in, out, opts...) if err != nil { return nil, err } @@ -704,7 +679,7 @@ func (c *streamerClient) RequestSong(ctx context.Context, in *SongRequest, opts func (c *streamerClient) SetConfig(ctx context.Context, in *StreamerConfig, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Streamer_SetConfig_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Streamer/SetConfig", in, out, opts...) if err != nil { return nil, err } @@ -713,7 +688,7 @@ func (c *streamerClient) SetConfig(ctx context.Context, in *StreamerConfig, opts func (c *streamerClient) Queue(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*QueueInfo, error) { out := new(QueueInfo) - err := c.cc.Invoke(ctx, Streamer_Queue_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Streamer/Queue", in, out, opts...) if err != nil { return nil, err } @@ -780,7 +755,7 @@ func _Streamer_Start_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Streamer_Start_FullMethodName, + FullMethod: "/radio.Streamer/Start", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StreamerServer).Start(ctx, req.(*emptypb.Empty)) @@ -798,7 +773,7 @@ func _Streamer_Stop_Handler(srv interface{}, ctx context.Context, dec func(inter } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Streamer_Stop_FullMethodName, + FullMethod: "/radio.Streamer/Stop", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StreamerServer).Stop(ctx, req.(*wrapperspb.BoolValue)) @@ -816,7 +791,7 @@ func _Streamer_RequestSong_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Streamer_RequestSong_FullMethodName, + FullMethod: "/radio.Streamer/RequestSong", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StreamerServer).RequestSong(ctx, req.(*SongRequest)) @@ -834,7 +809,7 @@ func _Streamer_SetConfig_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Streamer_SetConfig_FullMethodName, + FullMethod: "/radio.Streamer/SetConfig", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StreamerServer).SetConfig(ctx, req.(*StreamerConfig)) @@ -852,7 +827,7 @@ func _Streamer_Queue_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Streamer_Queue_FullMethodName, + FullMethod: "/radio.Streamer/Queue", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StreamerServer).Queue(ctx, req.(*emptypb.Empty)) @@ -892,13 +867,6 @@ var Streamer_ServiceDesc = grpc.ServiceDesc{ Metadata: "radio.proto", } -const ( - Queue_AddRequest_FullMethodName = "/radio.Queue/AddRequest" - Queue_ReserveNext_FullMethodName = "/radio.Queue/ReserveNext" - Queue_Remove_FullMethodName = "/radio.Queue/Remove" - Queue_Entries_FullMethodName = "/radio.Queue/Entries" -) - // QueueClient is the client API for Queue service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -919,7 +887,7 @@ func NewQueueClient(cc grpc.ClientConnInterface) QueueClient { func (c *queueClient) AddRequest(ctx context.Context, in *QueueEntry, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Queue_AddRequest_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Queue/AddRequest", in, out, opts...) if err != nil { return nil, err } @@ -928,7 +896,7 @@ func (c *queueClient) AddRequest(ctx context.Context, in *QueueEntry, opts ...gr func (c *queueClient) ReserveNext(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*QueueEntry, error) { out := new(QueueEntry) - err := c.cc.Invoke(ctx, Queue_ReserveNext_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Queue/ReserveNext", in, out, opts...) if err != nil { return nil, err } @@ -937,7 +905,7 @@ func (c *queueClient) ReserveNext(ctx context.Context, in *emptypb.Empty, opts . func (c *queueClient) Remove(ctx context.Context, in *QueueEntry, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Queue_Remove_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Queue/Remove", in, out, opts...) if err != nil { return nil, err } @@ -946,7 +914,7 @@ func (c *queueClient) Remove(ctx context.Context, in *QueueEntry, opts ...grpc.C func (c *queueClient) Entries(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*QueueInfo, error) { out := new(QueueInfo) - err := c.cc.Invoke(ctx, Queue_Entries_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/radio.Queue/Entries", in, out, opts...) if err != nil { return nil, err } @@ -1003,7 +971,7 @@ func _Queue_AddRequest_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Queue_AddRequest_FullMethodName, + FullMethod: "/radio.Queue/AddRequest", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueueServer).AddRequest(ctx, req.(*QueueEntry)) @@ -1021,7 +989,7 @@ func _Queue_ReserveNext_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Queue_ReserveNext_FullMethodName, + FullMethod: "/radio.Queue/ReserveNext", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueueServer).ReserveNext(ctx, req.(*emptypb.Empty)) @@ -1039,7 +1007,7 @@ func _Queue_Remove_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Queue_Remove_FullMethodName, + FullMethod: "/radio.Queue/Remove", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueueServer).Remove(ctx, req.(*QueueEntry)) @@ -1057,7 +1025,7 @@ func _Queue_Entries_Handler(srv interface{}, ctx context.Context, dec func(inter } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Queue_Entries_FullMethodName, + FullMethod: "/radio.Queue/Entries", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueueServer).Entries(ctx, req.(*emptypb.Empty)) diff --git a/templates/executor.go b/templates/executor.go index 5c9037b5..1fce0a74 100644 --- a/templates/executor.go +++ b/templates/executor.go @@ -32,7 +32,7 @@ type executor struct { ctx context.Context } -func NewExecutor(site *Site) Executor { +func newExecutor(site *Site) Executor { return &executor{ site: site, ctx: context.Background(), diff --git a/templates/loader.go b/templates/loader.go index 29bf2a15..aa14c949 100644 --- a/templates/loader.go +++ b/templates/loader.go @@ -56,7 +56,7 @@ type TemplateSelector interface { } func (s *Site) Executor() Executor { - return NewExecutor(s) + return newExecutor(s) } func (s *Site) ThemeNames() []string { @@ -252,7 +252,7 @@ func (tb ThemeBundle) Page(name string) (*TemplateBundle, error) { tlb, ok := tb.pages[name] if !ok { - return nil, errors.E(op, errors.TemplateUnknown) + return nil, errors.E(op, errors.TemplateUnknown, errors.Info(fmt.Sprintf("page: %s", name))) } return tlb, nil diff --git a/templates/loader_test.go b/templates/loader_test.go new file mode 100644 index 00000000..710c8e1a --- /dev/null +++ b/templates/loader_test.go @@ -0,0 +1,157 @@ +package templates_test + +import ( + "errors" + "io" + "io/fs" + "reflect" + "testing" + "testing/fstest" + "time" + + "github.com/R-a-dio/valkyrie/mocks" + "github.com/R-a-dio/valkyrie/templates" + "golang.org/x/tools/txtar" +) + +func randomFS(name string) *mocks.FSMock { + return &mocks.FSMock{ + OpenFunc: func(name string) (fs.File, error) { + return &mocks.FileMock{ + StatFunc: func() (fs.FileInfo, error) { + return &mocks.FileInfoMock{ + NameFunc: func() string { + return name + }, + SizeFunc: func() int64 { + return 1 + }, + ModeFunc: func() fs.FileMode { + return fs.FileMode(1) + }, + ModTimeFunc: func() time.Time { + return time.Now() + }, + IsDirFunc: func() bool { + return false + }, + SysFunc: func() any { + return nil + }, + }, nil + }, + ReadFunc: func(bytes []byte) (int, error) { + return -1, nil + }, + CloseFunc: func() error { return nil }, + }, nil + }, + } + +} + +// create a mock FS from a txtarchive +func txtarFS(a *txtar.Archive) fstest.MapFS { + mfs := make(fstest.MapFS) + for _, f := range a.Files { + mfs[f.Name] = &fstest.MapFile{ + Data: f.Data, + Mode: fs.ModePerm, + ModTime: time.Now(), + Sys: nil, + } + } + return mfs +} + +func txtarFSFromBytes(b []byte) fstest.MapFS { + return txtarFS(txtar.Parse(b)) +} + +func TestLoadThemes(t *testing.T) { + type args struct { + fsys fs.FS + } + tests := []struct { + name string + args args + want templates.Themes + wantErr bool + }{ + {"always error", args{&mocks.FSMock{ + OpenFunc: func(name string) (fs.File, error) { + return nil, errors.New("fucked") + }, + }}, nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := templates.LoadThemes(tt.args.fsys) + if (err != nil) != tt.wantErr { + t.Errorf("LoadThemes() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("LoadThemes() = %v, want %v", got, tt.want) + } + }) + } +} + +func FuzzLoadThemes(f *testing.F) { + testcases := []string{"wessie", "vin", "ed"} + for _, tc := range testcases { + f.Add(tc) + } + f.Fuzz(func(t *testing.T, name string) { + rfs := randomFS(name) + themes, err := templates.LoadThemes(rfs) + if err == nil || themes != nil { + t.Errorf("there should probably be an error for %s", name) + } + }) +} + +func TestExecuteTemplate(t *testing.T) { + type args struct { + fsys fs.FS + } + tests := []struct { + name string + args args + wantErr bool + shouldExec bool + }{ + {"empty", args{txtarFSFromBytes([]byte(` +-- base.tmpl -- +{{ define "base" }} +base +{{ template "empty" }} +{{ template "empty_part" }} +{{ end }} +-- default/default.tmpl -- +{{ define "empty" }} +{{ end }} +-- default/partials/empty.tmpl -- +{{ define "empty_part" }} +empty +{{ end }}`))}, false, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := templates.FromFS(tt.args.fsys) + if (err != nil) != tt.wantErr { + t.Errorf("FromFS() error = %v, wantErr %v", err, tt.wantErr) + return + } + if tt.shouldExec { + exec := got.Executor() + err = exec.ExecuteTemplate("default", "default", "base", io.Discard, nil) + if err != nil { + t.Errorf("template did not execute: %v", err) + return + } + } + }) + } +}