diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a156e0f9..ea911c86a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -81,25 +81,25 @@ jobs: run: | make build - - name: Verify core rendering (windows-latest) + - name: Test (windows-latest) if: matrix.step == 'check' && matrix.os == 'windows-latest' && always() shell: msys2 {0} env: MESA_GL_VERSION_OVERRIDE: 3.3COMPAT run: | - GL_CTX=-autoGlContext make verify-cores + GL_CTX=-autoGlContext make test verify-cores - - name: Verify core rendering (ubuntu-latest) + - name: Test (ubuntu-latest) if: matrix.step == 'check' && matrix.os == 'ubuntu-latest' && always() env: MESA_GL_VERSION_OVERRIDE: 3.3COMPAT run: | - GL_CTX=-autoGlContext xvfb-run --auto-servernum make verify-cores + GL_CTX=-autoGlContext xvfb-run --auto-servernum make test verify-cores - - name: Verify core rendering (macos-latest) + - name: Test (macos-latest) if: matrix.step == 'check' && matrix.os == 'macos-latest' && always() run: | - make verify-cores + make test verify-cores - uses: actions/upload-artifact@v3 if: matrix.step == 'check' && always() diff --git a/Makefile b/Makefile index f8097ac01..f0afe6ad7 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,8 @@ CGO_CFLAGS='-g -O3 -funroll-loops' CGO_LDFLAGS='-g -O3' GO_TAGS=static +.PHONY: clean test + fmt: @goimports -w cmd pkg tests @gofmt -s -w cmd pkg tests @@ -32,6 +34,9 @@ build.worker: build: build.coordinator build.worker +test: + go test -v ./pkg/... + verify-cores: go test -run TestAll ./pkg/worker/room -v -renderFrames $(GL_CTX) -outputPath "../../../_rendered" diff --git a/pkg/config/config.yaml b/pkg/config/config.yaml index 30737b082..1944c8f3f 100644 --- a/pkg/config/config.yaml +++ b/pkg/config/config.yaml @@ -205,6 +205,7 @@ emulator: nes: lib: nestopia_libretro roms: [ "nes" ] + scale: 3 snes: lib: snes9x_libretro roms: [ "smc", "sfc", "swc", "fig", "bs" ] diff --git a/pkg/worker/caged/libretro/frontend_test.go b/pkg/worker/caged/libretro/frontend_test.go index bf3c3c313..fc0f23418 100644 --- a/pkg/worker/caged/libretro/frontend_test.go +++ b/pkg/worker/caged/libretro/frontend_test.go @@ -9,6 +9,7 @@ import ( "os" "path" "path/filepath" + "runtime" "sync" "testing" "unsafe" @@ -16,7 +17,9 @@ import ( "github.com/giongto35/cloud-game/v3/pkg/config" "github.com/giongto35/cloud-game/v3/pkg/logger" "github.com/giongto35/cloud-game/v3/pkg/worker/caged/app" + "github.com/giongto35/cloud-game/v3/pkg/worker/caged/libretro/manager" "github.com/giongto35/cloud-game/v3/pkg/worker/caged/libretro/nanoarch" + "github.com/giongto35/cloud-game/v3/pkg/worker/thread" ) type testRun struct { @@ -44,6 +47,20 @@ type EmulatorPaths struct { save string } +var root string + +var syncOnce sync.Once + +func init() { + runtime.LockOSThread() + p, _ := filepath.Abs("../../../../") + root = p + string(filepath.Separator) +} + +func TestMain(m *testing.M) { + thread.Wrap(func() { os.Exit(m.Run()) }) +} + // GetEmulatorMock returns a properly stubbed emulator instance. // Due to extensive use of globals -- one mock instance is allowed per a test run. // Don't forget to init one image channel consumer, it will lock-out otherwise. @@ -55,12 +72,35 @@ func GetEmulatorMock(room string, system string) *EmulatorMock { if _, err := config.LoadConfig(&conf, ""); err != nil { panic(err) } + conf.Worker.Library.BasePath = filepath.FromSlash(root + "/assets/games") + + conf.Emulator.Libretro.Cores.Repo.ExtLock = + filepath.FromSlash(filepath.Join(root, "tests", ".cr", "cloud-game.lock")) + + conf.Emulator.Libretro.Cores.Paths.Libs = + filepath.FromSlash(root + conf.Emulator.Libretro.Cores.Paths.Libs) + conf.Emulator.LocalPath = filepath.FromSlash(filepath.Join(root, "tests", conf.Emulator.LocalPath)) + conf.Emulator.Storage = filepath.FromSlash(filepath.Join(root, "tests", "storage")) + + for k, config_ := range conf.Emulator.Libretro.Cores.List { + if config_.IsGlAllowed { + config_.AutoGlContext = true + } + conf.Emulator.Libretro.Cores.List[k] = config_ + } + + l := logger.Default() + + syncOnce.Do(func() { + if err := manager.CheckCores(conf.Emulator, l); err != nil { + l.Warn().Err(err).Msgf("a Libretro cores sync fail") + } + }) meta := conf.Emulator.GetLibretroCoreConfig(system) nano := nanoarch.NewNano(cleanPath(conf.Emulator.LocalPath)) - l := logger.Default() l2 := l.Extend(l.Level(logger.ErrorLevel).With()) nano.SetLogger(l2) @@ -115,10 +155,15 @@ func (emu *EmulatorMock) loadRom(game string) { log.Fatal(err) } w, h := emu.FrameSize() - if emu.conf.Scale == 0 { - emu.conf.Scale = 1 + + conf := emu.conf.GetLibretroCoreConfig(game) + + scale := 1.0 + if conf.Scale > 1 { + scale = conf.Scale } - emu.SetViewport(w, h, emu.conf.Scale) + emu.scale = scale + emu.SetViewport(w, h) } // Shutdown closes the emulator and cleans its resources. diff --git a/pkg/worker/caged/libretro/manager/http.go b/pkg/worker/caged/libretro/manager/http.go index 8609314e9..1f2dbc881 100644 --- a/pkg/worker/caged/libretro/manager/http.go +++ b/pkg/worker/caged/libretro/manager/http.go @@ -2,6 +2,7 @@ package manager import ( "os" + "path/filepath" "github.com/giongto35/cloud-game/v3/pkg/config" "github.com/giongto35/cloud-game/v3/pkg/logger" @@ -31,6 +32,15 @@ func NewRemoteHttpManager(conf config.LibretroConfig, log *logger.Logger) Manage } log.Debug().Msgf("Using .lock file: %v", fileLock) + if err := os.MkdirAll(filepath.Dir(fileLock), 0770); err != nil { + log.Error().Err(err).Msgf("couldn't create lock") + } else { + f, err := os.Create(fileLock) + if err != nil { + log.Error().Err(err).Msgf("couldn't create lock") + } + _ = f.Close() + } ar, err := arch.Guess() if err != nil { log.Error().Err(err).Msg("couldn't get Libretro core file extension") @@ -73,8 +83,16 @@ func CheckCores(conf config.Emulator, log *logger.Logger) error { func (m *Manager) Sync() error { // IPC lock if multiple worker processes on the same machine - m.fmu.Lock() - defer m.fmu.Unlock() + err := m.fmu.Lock() + if err != nil { + m.log.Error().Err(err).Msg("file lock fail") + } + defer func() { + err := m.fmu.Unlock() + if err != nil { + m.log.Error().Err(err).Msg("file unlock fail") + } + }() installed, err := m.GetInstalled(m.arch.LibExt) if err != nil { diff --git a/pkg/worker/room/room_test.go b/pkg/worker/room/room_test.go index 5d082229e..3ebeb51ba 100644 --- a/pkg/worker/room/room_test.go +++ b/pkg/worker/room/room_test.go @@ -255,6 +255,9 @@ func fixEmulators(config *config.WorkerConfig, autoGlContext bool) { config.Emulator.LocalPath = filepath.FromSlash(filepath.Join(root, "tests", config.Emulator.LocalPath)) config.Emulator.Storage = filepath.FromSlash(filepath.Join(root, "tests", "storage")) + config.Emulator.Libretro.Cores.Repo.ExtLock = + filepath.FromSlash(filepath.Join(root, "tests", ".cr", "cloud-game.lock")) + for k, conf := range config.Emulator.Libretro.Cores.List { if conf.IsGlAllowed && autoGlContext { conf.AutoGlContext = true diff --git a/pkg/worker/thread/mainthread_darwin_test.go b/pkg/worker/thread/mainthread_darwin_test.go index bab4a92c3..15ce9328f 100644 --- a/pkg/worker/thread/mainthread_darwin_test.go +++ b/pkg/worker/thread/mainthread_darwin_test.go @@ -1,16 +1,14 @@ package thread -import "testing" +import ( + "os" + "testing" +) -func init() { - runtime.LockOSThread() +func TestMain(m *testing.M) { + Wrap(func() { os.Exit(m.Run()) }) } func TestMainThread(t *testing.T) { - value := 0 - fn := func() { value = 1 } - Main(fn) - if value != 1 { - t.Errorf("wrong value %v", value) - } + _ = 10 }