forked from knative/func
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunction_migrations_unit_test.go
199 lines (172 loc) · 6.13 KB
/
function_migrations_unit_test.go
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package function
import (
"testing"
"time"
"github.com/coreos/go-semver/semver"
)
// TestMigrated ensures that the .Migrated() method returns whether or not the
// migrations were applied based on its self-reported .SpecVersion member.
func TestMigrated(t *testing.T) {
vNext := semver.New(LastSpecVersion())
vNext.BumpMajor()
tests := []struct {
name string
f Function
migrated bool
}{{
name: "no migration stamp",
f: Function{},
migrated: false, // function with no specVersion stamp should be not migrated.
}, {
name: "explicit small specVersion",
f: Function{SpecVersion: "0.0.1"},
migrated: false,
}, {
name: "latest specVersion",
f: Function{SpecVersion: LastSpecVersion()},
migrated: true,
}, {
name: "future specVersion",
f: Function{SpecVersion: vNext.String()},
migrated: true,
}}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.f.Migrated() != test.migrated {
t.Errorf("Expected %q.Migrated() to be %t when latest is %q",
test.f.SpecVersion, test.migrated, LastSpecVersion())
}
})
}
}
// TestMigrate ensures that functions have migrations apply the specVersion
// stamp on instantiation indicating migrations have been applied.
func TestMigrate(t *testing.T) {
// Load an old function, as it an earlier version it has registered migrations
// that will need to be applied.
root := "testdata/migrations/v0.19.0"
// Instantiate the function with the antiquated structure, which should cause
// migrations to be applied in order, and result in a function whose version
// compatibility is equivalent to the latest registered migration.
f, err := NewFunction(root)
if err != nil {
t.Fatal(err)
}
if f.SpecVersion != LastSpecVersion() {
t.Fatalf("Function was not migrated to %v on instantiation: specVersion is %v",
LastSpecVersion(), f.SpecVersion)
}
}
// TestMigrateToCreationStamp ensures that the creation timestamp migration
// introduced for functions 0.19.0 and earlier is applied.
func TestMigrateToCreationStamp(t *testing.T) {
// Load a function of version 0.19.0, which should have the migration applied
root := "testdata/migrations/v0.19.0"
now := time.Now()
f, err := NewFunction(root)
if err != nil {
t.Fatal(err)
}
if f.Created.Before(now) {
t.Fatalf("migration not applied: expected timestamp to be now, got %v.", f.Created)
}
}
// TestMigrateToBuilderImages ensures that the migration which migrates
// from "builder" and "builders" to "builderImages" is applied. This results
// in the attributes being removed and no errors on load of the function with
// old schema.
func TestMigrateToBuilderImagesDefault(t *testing.T) {
// Load a function created prior to the adoption of the builder images map
// (was created with 'builder' and 'builders' which does not support different
// builder implementations.
root := "testdata/migrations/v0.23.0"
// Without the migration, instantiating the older function would error
// because its strict unmarshalling would fail parsing the unexpected
// 'builder' and 'builders' members.
_, err := NewFunction(root)
if err != nil {
t.Fatal(err)
}
}
// TestMigrateToBuilderImagesCustom ensures that the migration to builderImages
// correctly carries forward a customized value for 'builder'.
func TestMigrateToBuilderImagesCustom(t *testing.T) {
// An early version of a function which includes a customized value for
// the 'builder'. This should be correctly carried forward to
// the namespaced 'builderImages' map as image for the "pack" builder.
root := "testdata/migrations/v0.23.0-customized"
expected := "example.com/user/custom-builder" // set in testdata func.yaml
f, err := NewFunction(root)
if err != nil {
t.Fatal(f)
}
i, ok := f.Build.BuilderImages["pack"]
if !ok {
t.Fatal("migrated function does not include the pack builder images")
}
if i != expected {
t.Fatalf("migrated function expected builder image '%v', got '%v'", expected, i)
}
}
// TestMigrateToSpecVersion ensures that a func.yaml file with a "version" field
// is migrated to use the field name "specVersion"
func TestMigrateToSpecVersion(t *testing.T) {
root := "testdata/migrations/v0.25.0"
f, err := NewFunction(root)
if err != nil {
t.Fatal(err)
}
if f.SpecVersion != LastSpecVersion() {
t.Fatal("migrated function does not include the Migration field")
}
}
// TestMigrateToSpecs ensures that the migration to the sub-specs format from
// the previous Function structure works
func TestMigrateToSpecs(t *testing.T) {
root := "testdata/migrations/v0.34.0"
expectedGit := Git{URL: "http://test-url", Revision: "test revision", ContextDir: "/test/context/dir"}
expectedNamespace := "test-namespace"
var expectedEnvs []Env
var expectedVolumes []Volume
f, err := NewFunction(root)
if err != nil {
t.Error(err)
t.Fatal(f)
}
if f.Build.Git != expectedGit {
t.Fatalf("migrated Function expected Git '%v', got '%v'", expectedGit, f.Build.Git)
}
if f.Deploy.Namespace != expectedNamespace {
t.Fatalf("migrated Function expected Namespace '%v', got '%v'", expectedNamespace, f.Deploy.Namespace)
}
if len(f.Run.Envs) != len(expectedEnvs) {
t.Fatalf("migrated Function expected Run Envs '%v', got '%v'", len(expectedEnvs), len(f.Run.Envs))
}
if len(f.Run.Volumes) != len(expectedVolumes) {
t.Fatalf("migrated Function expected Run Volumes '%v', got '%v'", len(expectedEnvs), len(f.Run.Envs))
}
}
// TestMigrateFromInvokeStructure tests that migration from f.Invocation.Format to
// f.Invoke works
func TestMigrateFromInvokeStructure(t *testing.T) {
root0 := "testdata/migrations/v0.35.0"
expectedInvoke := "" // empty because http is default and not written in yaml file
f0, err := NewFunction(root0)
if err != nil {
t.Error(err)
t.Fatal(f0)
}
if f0.Invoke != expectedInvoke {
t.Fatalf("migrated Function expected Invoke '%v', got '%v'", expectedInvoke, f0.Invoke)
}
root1 := "testdata/migrations/v0.35.0-nondefault"
expectedInvoke = "cloudevent"
f1, err := NewFunction(root1)
if err != nil {
t.Error(err)
t.Fatal(f1)
}
if f1.Invoke != expectedInvoke {
t.Fatalf("migrated Function expected Invoke '%v', got '%v'", expectedInvoke, f0.Invoke)
}
}