aboutsummaryrefslogtreecommitdiffstats
path: root/syz-cluster/pkg/service/sessiontest.go
blob: 2fa4d87019e53532816fbdc54b0d4c1683908d78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Copyright 2025 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package service

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/spanner"
	"github.com/google/syzkaller/syz-cluster/pkg/api"
	"github.com/google/syzkaller/syz-cluster/pkg/app"
	"github.com/google/syzkaller/syz-cluster/pkg/blob"
	"github.com/google/syzkaller/syz-cluster/pkg/db"
)

type SessionTestService struct {
	testRepo    *db.SessionTestRepository
	blobStorage blob.Storage
}

func NewSessionTestService(env *app.AppEnvironment) *SessionTestService {
	return &SessionTestService{
		testRepo:    db.NewSessionTestRepository(env.Spanner),
		blobStorage: env.BlobStorage,
	}
}

func (s *SessionTestService) Save(ctx context.Context, req *api.TestResult) error {
	entity, err := s.testRepo.Get(ctx, req.SessionID, req.TestName)
	if err != nil {
		return fmt.Errorf("failed to query the test: %w", err)
	} else if entity == nil {
		entity = &db.SessionTest{
			SessionID: req.SessionID,
			TestName:  req.TestName,
		}
	}
	logURI := entity.LogURI
	if len(req.Log) > 0 {
		logURI, err = s.blobStorage.Write(bytes.NewReader(req.Log),
			"Session", req.SessionID, "Test", req.TestName, "log")
		if err != nil {
			return fmt.Errorf("failed to save the log: %w", err)
		}
	}
	return s.testRepo.InsertOrUpdate(ctx, entity, func(test *db.SessionTest) {
		test.Result = req.Result
		test.UpdatedAt = time.Now()
		test.LogURI = logURI
		if req.BaseBuildID != "" {
			test.BaseBuildID = spanner.NullString{StringVal: req.BaseBuildID, Valid: true}
		}
		if req.PatchedBuildID != "" {
			test.PatchedBuildID = spanner.NullString{StringVal: req.PatchedBuildID, Valid: true}
		}
	})
}

func (s *SessionTestService) SaveArtifacts(ctx context.Context, sessionID, testName string, reader io.Reader) error {
	entity, err := s.testRepo.Get(ctx, sessionID, testName)
	if err != nil {
		return fmt.Errorf("failed to query the test: %w", err)
	} else if entity == nil {
		return fmt.Errorf("the test has not been submitted yet")
	}
	archiveURI, err := s.blobStorage.Write(reader, "Session", sessionID, "Test", testName, "artifacts")
	if err != nil {
		return fmt.Errorf("failed to save the artifacts archive: %w", err)
	}
	return s.testRepo.InsertOrUpdate(ctx, entity, func(test *db.SessionTest) {
		test.ArtifactsArchiveURI = archiveURI
	})
}