Skip to content

Commit 8edd0df

Browse files
committed
feat: basic lifecycle integraiton tests
1 parent 4f2f577 commit 8edd0df

File tree

1 file changed

+225
-2
lines changed

1 file changed

+225
-2
lines changed

client_int_test.go

+225-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
package function_test
44

55
import (
6+
"os"
7+
"reflect"
8+
"testing"
9+
"time"
10+
611
boson "github.com/boson-project/func"
12+
"github.com/boson-project/func/buildpacks"
13+
"github.com/boson-project/func/docker"
714
"github.com/boson-project/func/knative"
8-
"testing"
915
)
1016

1117
/*
@@ -35,7 +41,16 @@ import (
3541
./hack/delete.sh
3642
*/
3743

38-
const DefaultNamespace = "func"
44+
const (
45+
// DefaultRegistry must contain both the registry host and
46+
// registry namespace at this time. This will likely be
47+
// split and defaulted to the forthcoming in-cluster registry.
48+
DefaultRegistry = "localhost:5000/func"
49+
50+
// DefaultNamespace for the underlying deployments. Must be the same
51+
// as is set up and configured (see hack/configure.sh)
52+
DefaultNamespace = "func"
53+
)
3954

4055
func TestList(t *testing.T) {
4156
verbose := true
@@ -60,3 +75,211 @@ func TestList(t *testing.T) {
6075
t.Fatalf("Expected no Functions, got %v", names)
6176
}
6277
}
78+
79+
// TestNew creates
80+
func TestNew(t *testing.T) {
81+
defer within(t, "testdata/example.com/testnew")()
82+
verbose := true
83+
84+
client := newClient(verbose)
85+
86+
// Act
87+
if err := client.New(boson.Function{Name: "testnew", Root: ".", Runtime: "go"}); err != nil {
88+
t.Fatal(err)
89+
}
90+
defer del(t, client, "testnew")
91+
92+
// Assert
93+
names, err := client.List()
94+
if err != nil {
95+
t.Fatal(err)
96+
}
97+
if !reflect.DeepEqual(names, []string{"testnew"}) {
98+
t.Fatalf("Expected function list ['testnew'], got %v", names)
99+
}
100+
}
101+
102+
// TestDeploy updates
103+
func TestDeploy(t *testing.T) {
104+
defer within(t, "testdata/example.com/deploy")()
105+
verbose := true
106+
107+
client := newClient(verbose)
108+
109+
if err := client.New(boson.Function{Name: "deploy", Root: ".", Runtime: "go"}); err != nil {
110+
t.Fatal(err)
111+
}
112+
defer del(t, client, "deploy")
113+
114+
if err := client.Deploy("."); err != nil {
115+
t.Fatal(err)
116+
}
117+
}
118+
119+
// TestRemove deletes
120+
func TestRemove(t *testing.T) {
121+
defer within(t, "testdata/example.com/remove")()
122+
verbose := true
123+
124+
client := newClient(verbose)
125+
126+
if err := client.New(boson.Function{Name: "remove", Root: ".", Runtime: "go"}); err != nil {
127+
t.Fatal(err)
128+
}
129+
waitFor(t, client, "remove")
130+
131+
if err := client.Remove(boson.Function{Name: "remove"}); err != nil {
132+
t.Fatal(err)
133+
}
134+
135+
names, err := client.List()
136+
if err != nil {
137+
t.Fatal(err)
138+
}
139+
if len(names) != 0 {
140+
t.Fatalf("Expected empty Functions list, got %v", names)
141+
}
142+
}
143+
144+
// ***********
145+
// Helpers
146+
// ***********
147+
148+
// newClient creates an instance of the func client whose concrete impls
149+
// match those created by the kn func plugin CLI.
150+
func newClient(verbose bool) *boson.Client {
151+
builder := buildpacks.NewBuilder()
152+
builder.Verbose = verbose
153+
154+
pusher := docker.NewPusher()
155+
pusher.Verbose = verbose
156+
157+
deployer, err := knative.NewDeployer(DefaultNamespace)
158+
if err != nil {
159+
panic(err) // TODO: remove error from deployer constructor
160+
}
161+
deployer.Verbose = verbose
162+
163+
remover, err := knative.NewRemover(DefaultNamespace)
164+
if err != nil {
165+
panic(err) // TODO: remove error from remover constructor
166+
}
167+
remover.Verbose = verbose
168+
169+
lister, err := knative.NewLister(DefaultNamespace)
170+
if err != nil {
171+
panic(err) // TODO: remove error from lister constructor
172+
}
173+
lister.Verbose = verbose
174+
175+
return boson.New(
176+
boson.WithRegistry(DefaultRegistry),
177+
boson.WithVerbose(verbose),
178+
boson.WithBuilder(builder),
179+
boson.WithPusher(pusher),
180+
boson.WithDeployer(deployer),
181+
boson.WithRemover(remover),
182+
boson.WithLister(lister),
183+
)
184+
}
185+
186+
// Del cleans up after a test by removing a function by name.
187+
// (test fails if the named function does not exist)
188+
//
189+
// Intended to be run in a defer statement immediately after creation, del
190+
// works around the asynchronicity of the underlying platform's creation
191+
// step by polling the provider until the names function becomes available
192+
// (or the test times out), before firing off a deletion request.
193+
// Of course, ideally this would be replaced by the use of a synchronous
194+
// method, or at a minimum a way to register a callback/listener for the
195+
// creation event. This is what we have for now, and the show must go on.
196+
func del(t *testing.T, c *boson.Client, name string) {
197+
t.Helper()
198+
waitFor(t, c, name)
199+
if err := c.Remove(boson.Function{Name: name}); err != nil {
200+
t.Fatal(err)
201+
}
202+
}
203+
204+
// waitFor the named Function to become available in List output.
205+
// TODO: the API should be synchronous, but that depends first on
206+
// Create returning the derived name such that we can bake polling in.
207+
// Ideally the Boson provider's Creaet would be made syncrhonous.
208+
func waitFor(t *testing.T, c *boson.Client, name string) {
209+
t.Helper()
210+
var pollInterval = 2 * time.Second
211+
212+
for { // ever (i.e. defer to global test timeout)
213+
nn, err := c.List()
214+
if err != nil {
215+
t.Fatal(err)
216+
}
217+
for _, n := range nn {
218+
if n.Name == name {
219+
return
220+
}
221+
}
222+
time.Sleep(pollInterval)
223+
}
224+
}
225+
226+
// Create the given directory, CD to it, and return a function which can be
227+
// run in a defer statement to return to the original directory and cleanup.
228+
// Note must be executed, not deferred itself
229+
// NO: defer within(t, "somedir")
230+
// YES: defer within(t, "somedir")()
231+
func within(t *testing.T, root string) func() {
232+
t.Helper()
233+
cwd := pwd(t)
234+
mkdir(t, root)
235+
cd(t, root)
236+
return func() {
237+
cd(t, cwd)
238+
rm(t, root)
239+
}
240+
}
241+
242+
func pwd(t *testing.T) string {
243+
t.Helper()
244+
dir, err := os.Getwd()
245+
if err != nil {
246+
t.Fatal(err)
247+
}
248+
return dir
249+
}
250+
251+
func mkdir(t *testing.T, dir string) {
252+
t.Helper()
253+
if err := os.MkdirAll(dir, 0700); err != nil {
254+
t.Fatal(err)
255+
}
256+
}
257+
258+
func cd(t *testing.T, dir string) {
259+
t.Helper()
260+
if err := os.Chdir(dir); err != nil {
261+
t.Fatal(err)
262+
}
263+
}
264+
265+
func rm(t *testing.T, dir string) {
266+
t.Helper()
267+
if err := os.RemoveAll(dir); err != nil {
268+
t.Fatal(err)
269+
}
270+
}
271+
272+
func touch(file string) {
273+
_, err := os.Stat(file)
274+
if os.IsNotExist(err) {
275+
f, err := os.Create(file)
276+
if err != nil {
277+
panic(err)
278+
}
279+
defer f.Close()
280+
}
281+
t := time.Now().Local()
282+
if err := os.Chtimes(file, t, t); err != nil {
283+
panic(err)
284+
}
285+
}

0 commit comments

Comments
 (0)