repo_description: The container native, cloud agnostic serverless platform.
repo_topics: containers docker faas kubernetes lambda serverless serverless-functions swarm
code: package models
  
  import (
  	"reflect"
  	"testing"
  	"time"
  
  	"github.com/fnproject/fn/api/common"
  	"github.com/leanovate/gopter"
  	"github.com/leanovate/gopter/gen"
  	"github.com/leanovate/gopter/prop"
  )
  
  var stringType = reflect.TypeOf("")
  var intType = reflect.TypeOf(0)
  
  func appReflectType() reflect.Type {
  	app := App{}
  	return reflect.TypeOf(app)
  }
  
  func configGenerator() gopter.Gen {
  	return gen.MapOf(gen.AlphaString(), gen.AlphaString()).Map(func(m map[string]string) Config {
  		return Config(m)
  	})
  }
  
  func annotationGenerator() gopter.Gen {
  	annotation1, _ := EmptyAnnotations().With("anAnnotation1", "value1")
  	annotation2, _ := EmptyAnnotations().With("anAnnotation2", "value2")
  
  	return gen.OneConstOf(annotation1, annotation2)
  }
  
  func datetimeGenerator() gopter.Gen {
  	return gen.Time().Map(func(t time.Time) common.DateTime {
  		return common.DateTime(t)
  	})
  }
  
  func appFieldGenerators(t *testing.T) map[string]gopter.Gen {
  	fieldGens := make(map[string]gopter.Gen)
  	fieldGens["ID"] = gen.AlphaString()
  	fieldGens["Name"] = gen.AlphaString()
  	fieldGens["Config"] = configGenerator()
  	fieldGens["Annotations"] = annotationGenerator()
  	fieldGens["Shape"] = gen.Const("")
  	fieldGens["SyslogURL"] = gen.AlphaString().Map(func(s string) *string {
  		return &s
  	})
  	fieldGens["CreatedAt"] = datetimeGenerator()
  	fieldGens["UpdatedAt"] = datetimeGenerator()
  
  	appFieldCount := appReflectType().NumField()
  
  	if appFieldCount != len(fieldGens) {
  		t.Fatalf("App struct field count, %d, does not match app generator field count, %d", appFieldCount, len(fieldGens))
  	}
  
  	return fieldGens
  }
  
  func appGenerator(t *testing.T) gopter.Gen {
  	return gen.Struct(appReflectType(), appFieldGenerators(t))
  }
  
  func novelValue(t *testing.T, originalInstance reflect.Value, fieldName string, fieldGen gopter.Gen) (interface{}, reflect.Value) {
  	newValue, result := fieldGen.Sample()
  	if !result {
  		t.Fatalf("Error sampling field generator, %s, %v", fieldName, result)
  	}
  
  	field := originalInstance.FieldByName(fieldName)
  	currentValue := field.Interface()
  
  	for i := 0; i < 100; i++ {
  		if fieldName == "Annotations" {
  			if !newValue.(Annotations).Equals(currentValue.(Annotations)) {
  				break
  			}
  		} else if fieldName == "Config" {
  			if !newValue.(Config).Equals(currentValue.(Config)) {
  				break
  			}
  		} else {
  			if newValue != currentValue {
  				break
  			}
  		}
  		newValue, result = fieldGen.Sample()
  		if !result {
  			t.Fatalf("Error sampling field generator, %s, %v", fieldName, result)
  		}
  
  		if i == 99 {
  			t.Fatalf("Failed to generate a novel value for field, %s", fieldName)
  		}
  	}
  	return currentValue, reflect.ValueOf(newValue)
  }
  
  func TestAppEquality(t *testing.T) {
  	properties := gopter.NewProperties(nil)
  
  	properties.Property("An app should always equal itself", prop.ForAll(
  		func(app App) bool {
  			return app.Equals(&app)
  		},
  		appGenerator(t),
  	))
  
  	properties.Property("An app should always equal a clone of itself", prop.ForAll(
  		func(app App) bool {
  			clone := app.Clone()
  			return app.Equals(clone)
  		},
  		appGenerator(t),
  	))
  
  	appFieldGens := appFieldGenerators(t)
  
  	properties.Property("An app should never match a modified version of itself", prop.ForAll(
  		func(app App) bool {
  			for fieldName, fieldGen := range appFieldGens {
  
  				if fieldName == "CreatedAt" ||
  					fieldName == "UpdatedAt" || fieldName == "Shape" {
  					continue
  				}
  
  				currentValue, newValue := novelValue(t, reflect.ValueOf(app), fieldName, fieldGen)
  
  				clone := app.Clone()
  				s := reflect.ValueOf(clone).Elem()
  				field := s.FieldByName(fieldName)
  
  				field.Set(newValue)
  
  				if app.Equals(clone) {
  					t.Errorf("Changed field, %s, from {%v} to {%v}, but still equal.", fieldName, currentValue, newValue)
  					return false
  				}
  			}
  			return true
  		},
  		appGenerator(t),
  	))
  
  	properties.TestingRun(t)
  }
  
  func TestValidateAppName(t *testing.T) {
  	tooLongName := "7"
  	for i := 0; i < MaxLengthAppName+1; i++ {
  		tooLongName += "7"
  	}
  
  	testCases := []struct {
  		Name string
  		Want error
  	}{
  		{"valid_name-101", nil},
  		{tooLongName, ErrAppsTooLongName},
  		{"", ErrMissingName},
  		{"invalid.character", ErrAppsInvalidName},
  	}
  
  	for _, testCase := range testCases {
  		app := App{Name: testCase.Name}
  		got := app.ValidateName()
  
  		if got != testCase.Want {
  			t.Errorf(
  				"App.ValidateName() failed for %q - wanted: %q but got: %q",
  				testCase.Name, testCase.Want, got)
  		}
  	}
  }
  
  func TestValidateApp(t *testing.T) {
  	valid_name := "valid_name"
  	valid_syslog := "tcp://localhost:13371"
  
  	testCases := []struct {
  		App  App
  		Want error
  	}{
  		{App{Name: valid_name, SyslogURL: &valid_syslog}, nil},
  		{App{Name: ""}, ErrMissingName},
  	}
  
  	for _, testCase := range testCases {
  		got := testCase.App.Validate()
  
  		if got != testCase.Want {
  			t.Errorf("App.Validate() failed for '%+v' - wanted: %q but got: %q",
  				testCase.App, testCase.Want, got)
  		}
  	}
  }
  