You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在GitHub Actions中运行Go脚本时出现Permission Denied错误求助

问题:GitHub Actions中Go测试因硬件命令不可用失败

我有一个Go项目,用于提供Debian系列发行版的CPU温度、时钟频率等系统信息接口。本地构建和测试都正常,但在GitHub Actions中执行测试时失败,Shell脚本返回错误码1。

相关Go函数

//GetTemp returns the current CPU temperature in C
func GetTemp() (temp float64, err error) {
    cmd := exec.Command("bash", "-c", "/usr/bin/vcgencmd measure_temp | egrep -o '[0-9]*\\.[0-9]*'")
    out, err := cmd.Output()
    if err != nil {
        return -1, err
    }
    res := strings.TrimSuffix(string(out), "\n")
    temp, _ = strconv.ParseFloat(res, 64)
    return temp, nil
}

对应测试函数

func TestTempRange(t *testing.T) {
    expectedMin, expectedMax := 0.0, 120.0
    actual, err := GetTemp()
    if err != nil {
        t.Fatalf("Error retrieving cpu temp\nError: %v", err)
    }

    if actual < expectedMin || actual > expectedMax {
        t.Fatalf("return temp outside of acceptable range.\nExpected temp within range [%v, %v]\nRecieved %v", expectedMin, expectedMax, actual)
    }
}

GitHub Actions构建配置

jobs:

  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        go-version: [ '1.14', '1.15', '1.16.x' ]
        
    steps:
    - uses: actions/checkout@v3

    - name: Set up Go
      uses: actions/setup-go@v3
      with:
        go-version: ${{ matrix.go-version }}
        
    - name: Install dependencies
      run: go get .

    - name: Build
      run: go build -v ./...

    - name: Test with Go
      run: go test -json > TestResults-${{ matrix.go-version }}.json
      
    - name: Upload Go test results
      uses: actions/upload-artifact@v3
      with:
        name: Go-results-${{ matrix.go-version }}
        path: TestResults-${{ matrix.go-version }}.json

GitHub Actions错误输出

Run go test `go list ./... | grep -v examples` -coverprofile=coverage.txt -covermode=atomic
?       github.com/rafaelzasas/rpiSystemMonitor [no test files]
--- FAIL: TestTempRange (0.02s)
    cpu_test.go:9: Error retrieving cpu temp
        Error: exit status 1
--- FAIL: TestFreqRange (0.03s)
    cpu_test.go:22: Error retrieving cpu freq
        Error: exit status 1
FAIL
coverage: 57.1% of statements
FAIL    github.com/rafaelzasas/rpiSystemMonitor/cpu 0.047s
ok      github.com/rafaelzasas/rpiSystemMonitor/mem 0.044s  coverage: 42.9% of statements
FAIL
Error: Process completed with exit code 1.

问题原因与解决办法

核心原因

GitHub Actions使用的ubuntu-latest是x86架构的标准虚拟机,而vcgencmd是树莓派(ARM架构)专属的硬件查询工具,在普通Ubuntu环境中不存在,这是测试失败的根本原因。

可行解决方案

1. 跳过硬件相关测试

在测试命令中排除包含硬件调用的包,修改GitHub Actions的测试步骤:

go test $(go list ./... | grep -v cpu) -json > TestResults-${{ matrix.go-version }}.json

或者在测试代码中添加环境判断,自动跳过非树莓派环境的测试:

func TestTempRange(t *testing.T) {
    // 检查vcgencmd是否存在,不存在则跳过测试
    if _, err := exec.LookPath("vcgencmd"); err != nil {
        t.Skip("vcgencmd not found, skipping hardware-dependent test")
    }
    // 原有测试逻辑
    expectedMin, expectedMax := 0.0, 120.0
    actual, err := GetTemp()
    if err != nil {
        t.Fatalf("Error retrieving cpu temp\nError: %v", err)
    }

    if actual < expectedMin || actual > expectedMax {
        t.Fatalf("return temp outside of acceptable range.\nExpected temp within range [%v, %v]\nRecieved %v", expectedMin, expectedMax, actual)
    }
}

2. Mock硬件调用逻辑

重构代码,将硬件查询逻辑抽象为接口,测试时用Mock实现替代真实调用:

  • 定义接口:
    type SystemInfoGetter interface {
        GetTemp() (float64, error)
    }
    
  • 真实环境实现:
    type RealSystemInfo struct{}
    
    func (r RealSystemInfo) GetTemp() (float64, error) {
        cmd := exec.Command("bash", "-c", "/usr/bin/vcgencmd measure_temp | egrep -o '[0-9]*\\.[0-9]*'")
        out, err := cmd.Output()
        if err != nil {
            return -1, err
        }
        res := strings.TrimSuffix(string(out), "\n")
        temp, _ := strconv.ParseFloat(res, 64)
        return temp, nil
    }
    
  • 测试用Mock实现:
    type MockSystemInfo struct{}
    
    func (m MockSystemInfo) GetTemp() (float64, error) {
        return 50.0, nil // 返回合法测试值
    }
    
  • 修改测试函数使用Mock:
    func TestTempRange(t *testing.T) {
        getter := MockSystemInfo{}
        expectedMin, expectedMax := 0.0, 120.0
        actual, err := getter.GetTemp()
        if err != nil {
            t.Fatalf("Error retrieving cpu temp\nError: %v", err)
        }
    
        if actual < expectedMin || actual > expectedMax {
            t.Fatalf("return temp outside of acceptable range.\nExpected temp within range [%v, %v]\nRecieved %v", expectedMin, expectedMax, actual)
        }
    }
    

3. 使用ARM架构运行环境

在GitHub Actions中配置ARM架构的Runner或用QEMU模拟树莓派环境,这种方式配置复杂且运行速度较慢,仅适合必须测试真实硬件逻辑的场景。

内容的提问来源于stack exchange,提问作者Rafael Zasas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 15:15:46