-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdb_test.go
More file actions
157 lines (129 loc) · 4.84 KB
/
Copy pathdb_test.go
File metadata and controls
157 lines (129 loc) · 4.84 KB
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// (c) Siemens AG 2023
//
// SPDX-License-Identifier: MIT
package ieddata
import (
"context"
"database/sql"
"fmt"
"os"
"path"
"strconv"
"time"
"github.com/jmoiron/sqlx"
"golang.org/x/sys/unix"
"modernc.org/sqlite/vfs"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gleak"
. "github.com/thediveo/fdooze"
. "github.com/thediveo/success"
)
var _ = Describe("IED app engine database", func() {
BeforeEach(func() {
if os.Getuid() != 0 {
Skip("needs root")
}
goodgos := Goroutines()
goodfds := Filedescriptors()
DeferCleanup(func() {
// There's a whale watcher in the background needing to wind, so we
// give it a chance to get scheduled and run its course.
Eventually(Goroutines).WithTimeout(2 * time.Second).WithPolling(250 * time.Millisecond).
ShouldNot(HaveLeaked(goodgos))
Expect(Filedescriptors()).NotTo(HaveLeakedFds(goodfds))
})
})
Context("ensure that the sqlite database driver infrastructure is working", func() {
DescribeTable("opening db via different paths",
func(fn func() (*sqlx.DB, error)) {
db, err := fn()
Expect(err).NotTo(HaveOccurred())
defer func() { _ = db.Close() }()
Expect(db.Ping()).To(Succeed())
appdb := &AppEngineDB{DB: db}
apps := Successful(appdb.Apps())
Expect(apps).To(ContainElements(
And(HaveField("Title", "AppA"),
HaveField("RepositoryName", "aaa")),
And(HaveField("Title", "AppC"),
HaveField("RepositoryName", "ccc"))))
},
Entry("plain", func() (*sqlx.DB, error) {
return sqlx.Open(dbDriverName, "tests/sqlite-alpine-appengine-db/test-apps-and-device.db")
}),
Entry("via /proc/$PID/root", func() (*sqlx.DB, error) {
dbpath := path.Clean(fmt.Sprintf("/proc/%d/root/", os.Getpid()) +
Successful(unix.Getwd()) +
"/tests/sqlite-alpine-appengine-db/test-apps-and-device.db")
return sqlx.Open(dbDriverName, dbpath)
}),
)
})
It("sanitizes database names", func() {
Expect(sanitize("abcxyz.0-9")).To(Equal("abcxyz.0-9"))
Expect(sanitize("../abc?foo=bar")).To(Equal("__abc_foo_bar"))
})
It("fails for invalid container PID", func() {
Expect(OpenInPID("foo.db", 0)).Error().To(MatchError(MatchRegexp(`no such file or directory`)))
})
It("fails for missing IE runtime container", func(ctx context.Context) {
Expect(fakecore.Rename(ctx, "off-"+EdgeIotCoreContainerName)).To(Succeed())
DeferCleanup(func(ctx context.Context) {
Expect(fakecore.Rename(ctx, EdgeIotCoreContainerName)).To(Succeed())
})
Expect(Open("foo.db")).Error().To(MatchError(MatchRegexp(`no .* runtime container`)))
})
It("fails for missing/invalid IED app engine database", func() {
Expect(Open("foo.db")).Error().To(MatchError(ContainSubstring("/root/data")))
Expect(Open("not.a.db")).Error().To(MatchError(ContainSubstring("nable to open database")))
})
It("accesses the app engine database", func() {
db := Successful(Open(PlatformBoxDb))
defer func() { _ = db.Close() }()
rows := Successful(db.Query("SELECT deviceKey, deviceValue from device"))
defer func() { Expect(rows.Close()).To(Succeed()) }()
m := map[string]string{}
for rows.Next() {
var key, value string
Expect(rows.Scan(&key, &value)).To(Succeed())
m[key] = value
}
Expect(m).To(HaveKeyWithValue("deviceName", "iedx12345"))
Expect(m).To(HaveKeyWithValue("ownerEmail", "foo.bar@example.com"))
})
Context("doing weird things with os.Root on /proc/PID/root", func() {
It("reads a db via vfs on /proc/PID/root", func() {
By("creating a temporary directory for a test database")
tmpdbdir := Successful(os.MkdirTemp("", "canarydb-*"))
defer func() { _ = os.RemoveAll(tmpdbdir) }()
const dbname = "canary.db"
By("creating the testing database")
func() {
db := Successful(sql.Open(dbDriverName,
"file:"+path.Join(tmpdbdir, dbname)))
defer func() { Expect(db.Close()).To(Succeed()) }()
Expect(db.Exec("create table 'test' ('name' varchar(32) not null, primary key('name') )")).
Error().NotTo(HaveOccurred())
Expect(db.Exec("insert into 'test' (name) values ('foobar')")).
Error().NotTo(HaveOccurred())
}()
By("opening the db via VFS")
root := Successful(os.OpenRoot(
path.Join("/proc", strconv.FormatInt(int64(os.Getpid()), 10), "root", tmpdbdir)))
defer func() { Expect(root.Close()).To(Succeed()) }()
vfsid, sqlvfs := Successful2R(vfs.New(root.FS()))
defer func() { Expect(sqlvfs.Close()).To(Succeed()) }()
db := Successful(sqlx.Open(dbDriverName, dbname+"?vfs="+vfsid))
defer func() { Expect(db.Close()).To(Succeed()) }()
Expect(db.Ping()).To(Succeed())
By("reading a row from the read-only db")
rows := Successful(db.Query("select * from 'test'"))
defer func() { Expect(rows.Close()).To(Succeed()) }()
Expect(rows.Next()).To(BeTrue())
var name string
Expect(rows.Scan(&name)).To(Succeed())
Expect(name).To(Equal("foobar"))
})
})
})