diff options
author | MrArmonius <mrarmonius@gmail.com> | 2021-07-16 16:56:56 +0200 |
---|---|---|
committer | MrArmonius <mrarmonius@gmail.com> | 2021-07-19 18:57:40 +0200 |
commit | 9a8c19ec0f9b2f09daab244a49c67904c5c086aa (patch) | |
tree | f30c61228022493823ca812b292fee2285b2d233 /test_automatic | |
parent | da627ac39ad437bfb6be7e5f343933a0ca4e5073 (diff) | |
download | bottin-9a8c19ec0f9b2f09daab244a49c67904c5c086aa.tar.gz bottin-9a8c19ec0f9b2f09daab244a49c67904c5c086aa.zip |
Bottin's Test V2.0 with Framework Testing
V2 the test end-to-end,
Tests made similar to V1.0,
Add the possibility to pararellize the tests,
Create an environnement for easy integration of news test,
Diffstat (limited to 'test_automatic')
-rw-r--r-- | test_automatic/Scan_Bad_Packets.pcapng | bin | 646080 -> 0 bytes | |||
-rw-r--r-- | test_automatic/Scan_Good_Packets.pcapng | bin | 1303556 -> 0 bytes | |||
-rw-r--r-- | test_automatic/config.json.test | 13 | ||||
-rw-r--r-- | test_automatic/go.mod | 8 | ||||
-rw-r--r-- | test_automatic/go.sum | 23 | ||||
-rw-r--r-- | test_automatic/integration.go | 431 | ||||
-rw-r--r-- | test_automatic/rapport_beug_bottin.txt | 40 | ||||
-rwxr-xr-x | test_automatic/start_test.sh | 12 |
8 files changed, 0 insertions, 527 deletions
diff --git a/test_automatic/Scan_Bad_Packets.pcapng b/test_automatic/Scan_Bad_Packets.pcapng Binary files differdeleted file mode 100644 index cc209f5..0000000 --- a/test_automatic/Scan_Bad_Packets.pcapng +++ /dev/null diff --git a/test_automatic/Scan_Good_Packets.pcapng b/test_automatic/Scan_Good_Packets.pcapng Binary files differdeleted file mode 100644 index 5c87f82..0000000 --- a/test_automatic/Scan_Good_Packets.pcapng +++ /dev/null diff --git a/test_automatic/config.json.test b/test_automatic/config.json.test deleted file mode 100644 index bc1eeec..0000000 --- a/test_automatic/config.json.test +++ /dev/null @@ -1,13 +0,0 @@ -{ - "suffix": "dc=deuxfleurs,dc=fr", - "bind": "127.0.0.1:1389", - "acl": [ - "ANONYMOUS::bind:*,ou=users,dc=deuxfleurs,dc=fr:", - "ANONYMOUS::bind:cn=admin,dc=deuxfleurs,dc=fr:", - "*,dc=deuxfleurs,dc=fr::read:*:* !userpassword", - "*::read modify:SELF:*", - "cn=admin,dc=deuxfleurs,dc=fr::read add modify delete:*:*", - "*:cn=admin,ou=groups,dc=deuxfleurs,dc=fr:read add modify delete:*:*" - ] -} - diff --git a/test_automatic/go.mod b/test_automatic/go.mod deleted file mode 100644 index 74ed1ce..0000000 --- a/test_automatic/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module bottin/integration - -go 1.14 - -require ( - github.com/go-ldap/ldap/v3 v3.3.0 - github.com/sirupsen/logrus v1.4.2 -) diff --git a/test_automatic/go.sum b/test_automatic/go.sum deleted file mode 100644 index 8e94420..0000000 --- a/test_automatic/go.sum +++ /dev/null @@ -1,23 +0,0 @@ -github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= -github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8= -github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ= -github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/test_automatic/integration.go b/test_automatic/integration.go deleted file mode 100644 index d55d280..0000000 --- a/test_automatic/integration.go +++ /dev/null @@ -1,431 +0,0 @@ -package main - -import ( - "github.com/go-ldap/ldap/v3" - "fmt" - log "github.com/sirupsen/logrus" - "math/rand" - "strings" - "errors" - "os" -) - - -const bindusername = "cn=admin,dc=deuxfleurs,dc=fr" -const adresse = "127.0.0.1" -const port = 1389 -var bindpassword string - -var all_names = make(map[string]struct{}) - - - -func printError(LDAPError error) { - if LDAPError != nil { - log.Fatal(LDAPError) - } -} - -func createOU(l *ldap.Conn) error { - - req := ldap.NewAddRequest("ou=groups,dc=deuxfleurs,dc=fr",nil) - req.Attribute("description",[]string{"OrganizationalUnit qui regroupe tous les groupes"}) - req.Attribute("objectclass",[]string{"organizationalUnit", "top"}) - req.Attribute("ou",[]string{"groups"}) - req.Attribute("structuralobjectclass", []string{"organizationalUnit"}) - - err := l.Add(req) - if err != nil { - return err - } - - req = ldap.NewAddRequest("ou=users,dc=deuxfleurs,dc=fr",nil) - req.Attribute("description",[]string{"OrganizationalUnit qui regroupe tous les utilisateurs"}) - req.Attribute("objectclass",[]string{"organizationalUnit", "top"}) - req.Attribute("ou",[]string{"users"}) - req.Attribute("structuralobjectclass", []string{"organizationalUnit"}) - - err = l.Add(req) - return err -} - -func generateName(r *rand.Rand) (name string) { - for only_one := true; only_one; _, only_one = all_names[name]{ - name = fmt.Sprintf("%d",r.Int()) - } - all_names[name] = struct{}{} - log.Debug(fmt.Sprintf("Name generated: %s.\n", name)) - return -} - -func createGroup(r *rand.Rand, l *ldap.Conn) (tab_AddRequest []ldap.AddRequest, err error) { - StructuralObjectClass := []string{"groupOfNames"} - ObjectClass := []string{"groupOfNames","top"} - - - - for i := 0; i<20; i++ { - //Generate name and check if he is unique - name := generateName(r) - - req := ldap.NewAddRequest(fmt.Sprintf("cn=%s,ou=groups,dc=deuxfleurs,dc=fr",name),nil) - req.Attribute("description",[]string{generateName(r)}) - req.Attribute("objectclass",ObjectClass) - req.Attribute("structuralobjectclass",StructuralObjectClass) - - err = l.Add(req) - if err != nil { - log.Warn(fmt.Sprintf("Erreur survenue sur la création du [%d] groupe.\n",i)) - return nil, err - } - tab_AddRequest = append(tab_AddRequest, *req) - - } - return -} - -func createUser(r *rand.Rand, l *ldap.Conn) (tab_AddRequest []ldap.AddRequest, err error) { - StructuralObjectClass := []string{"inetOrgPerson"} - ObjectClass := []string{"inetOrgPerson","organizationalPerson","person","top"} - - for i := 0; i<20; i++ { - name := generateName(r) - - req := ldap.NewAddRequest(fmt.Sprintf("cn=%s,ou=users,dc=deuxfleurs,dc=fr",name),nil) - req.Attribute("displayname",[]string{generateName(r)}) - req.Attribute("objectclass",ObjectClass) - req.Attribute("structuralobjectclass",StructuralObjectClass) - - err = l.Add(req) - if err != nil { - log.Warn(fmt.Sprintf("Erreur survenue sur la création du [%d] user.\n",i)) - return nil, err - } - tab_AddRequest = append(tab_AddRequest, *req) - - } - return -} - -func search_attributes(tab_Attributes []ldap.Attribute, tipe string) (*ldap.Attribute) { - for _,att := range tab_Attributes { - if att.Type == tipe { - return &att - } - } - return nil -// return ldap.Attribute{} -} - -func test_attributes(l *ldap.Conn, tab_AddRequest []ldap.AddRequest, filter_objectclass, user_or_group string) (err error) { - for _, addRequest := range tab_AddRequest { - - //On prend le cn en supposant qu'il est unique - cn := strings.Split(addRequest.DN,",")[0] - - //On crée la requête pour la recherche - search_req := ldap.NewSearchRequest( - fmt.Sprintf("ou=%s,dc=deuxfleurs,dc=fr",user_or_group), - ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, - fmt.Sprintf("(&(objectclass=%s)(%s))", filter_objectclass,cn), - []string{"displayname","objectclass","structuralobjectclass"}, - nil, - ) - - //On lance la recherche - result, err := l.Search(search_req) - if err != nil { - return err - } - if len(result.Entries) != 1 { - return errors.New("Test a trouvé plusieurs displaynames en commun ou en a trouvé aucun") - } - - //On compare les attributs qu'on a reçu avec les attributs qu'on a envoyé - result_attributes := result.Entries[0].Attributes - log.Debug(fmt.Sprintf("La longueur est de %d, contient : \n %s.\n",len(result_attributes), result_attributes)) - - //Notre recherche crée un attribut par valeur, même si les valeurs viennent du même nom d'attribut - //Par exemple: objectclass possède 4 valeurs. Alors on aura 4 EntryAttribute qui contient chacune une des 4 valeurs de l'attribut objectclass - - //j est l'indice qui représente la j-ème valeur de notre attribut - var j int - var att *ldap.Attribute - for i,attributes := range result_attributes { - //On cherche l'attribut de l'user i qui a le même nom que celui qu'on a reçu et qu'on traite dans cette boucle - if j == 0 { - att = search_attributes(addRequest.Attributes, attributes.Name) - if att == nil { - return errors.New(fmt.Sprintf("Error: test_attributes - Don't find match name attributes. We search %s.\n", attributes.Name)) - } - } - log.Debug(fmt.Sprintf("Le nom de l'attribut est %s, sa valeur est: \n %s.", att.Type, att)) - - if j >= len(att.Vals) || att.Vals[j] != attributes.Values[0] { - return errors.New(fmt.Sprintf("Error: test_attributes - Theses values aren't the same: %d, %d",att.Vals, attributes.Values)) - } - - if i+1 < len(result_attributes) && result_attributes[i+1].Name == attributes.Name { - j += 1 - } else { j = 0} - } - - } - return nil -} - -func clean(l *ldap.Conn, AddReq_users, AddReq_groups []ldap.AddRequest,user, group bool) (err error){ - log.Debug("Debut clean") - if(user) { - for _,req := range AddReq_users { - delReq := ldap.NewDelRequest(req.DN,nil) - err = l.Del(delReq) - if err != nil { - return - } - } - } - if group { - for _,req := range AddReq_groups { - delReq := ldap.NewDelRequest(req.DN, nil) - err = l.Del(delReq) - if err != nil { - return - } - } - } - defer log.Debug("Fin clean") - return -} - -func test_modify_attributes(l *ldap.Conn, r *rand.Rand, tab_AddReq []ldap.AddRequest, tab_type_name []string) (err error) { - for _, AddReq := range tab_AddReq { - modReq := ldap.NewModifyRequest(AddReq.DN,nil) - for _, type_name := range tab_type_name { - newName := generateName(r) - modReq.Replace(type_name, []string{newName}) - att := search_attributes(AddReq.Attributes, type_name) - att.Vals[0] = newName - } - err = l.Modify(modReq) - if err != nil { - return - } - - } - return -} - -func add_user_in_groups(l *ldap.Conn, r *rand.Rand, users, groups []ldap.AddRequest) (err error) { - for _,group := range groups { - numberUsers := r.Intn(19) + 1 //Always a minimum of 1 user - list_users := []string{} - for i:=0; i < numberUsers; i++ { - list_users = append(list_users, users[i].DN) - } - modifyReq := ldap.NewModifyRequest( group.DN, nil) - modifyReq.Add("member", list_users) - - err = l.Modify(modifyReq) - if err != nil { - log.Warn(fmt.Sprintf("Error: ModifyReq failed, func:add_users_in_groups from group:\n %d",group)) - return - } - } - return -} - -func delete_groups(l *ldap.Conn, groups []ldap.AddRequest) (list map[string][]string ,err error) { - list = make(map[string][]string) - for _, group := range groups { - //Get lists_users - cn := strings.Split(group.DN,",")[0] - search_req := ldap.NewSearchRequest( - "ou=groups,dc=deuxfleurs,dc=fr", - ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, - fmt.Sprintf("(&(objectclass=groupOfNames)(%s))",cn), - []string{"member"}, - nil, - ) - res , err := l.Search(search_req) - if err != nil { - log.Warn(fmt.Sprintf("Error Search: func: delete_groups_and_check_memberOf, from group: \n %d", group)) - return list, err - } - if len(res.Entries) != 1 { - err = errors.New(fmt.Sprintf("SearchResult get: %s, SearchResult wanted: 1", len(res.Entries))) - return list, err - } - EntryAtt := res.Entries[0].Attributes - list_users := []string{} - for _, att := range EntryAtt { - list_users = append(list_users ,att.Values[0]) - } - - //Del group - del := ldap.NewDelRequest( group.DN, nil) - err = l.Del(del) - if err != nil { - return list, err - } - list[group.DN] = list_users - } - return -} - -func check_memberOf(l *ldap.Conn, list map[string][]string) (err error) { - //Check the memberOf of all users - for groupeDN,_ := range list{ - search_req := ldap.NewSearchRequest( - "ou=users,dc=deuxfleurs,dc=fr", - ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,0 ,0, false, - fmt.Sprintf("(&(objectclass=inetOrgPerson)(memberOf=%s))",groupeDN), - []string{"cn"}, - nil, - ) - res, err := l.Search(search_req) - if err != nil { - return err - } - if len(res.Entries) != 0 { - err = errors.New(fmt.Sprintf("L'user '%s' a encore le DN d'un groupe supprimé: %s",res.Entries[0].Attributes[0].Values[0],groupeDN)) - return err - } - } - return err -} - -func reconnect(l *ldap.Conn) (l_nouv *ldap.Conn, err error){ - l.Close() - l_nouv, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d",adresse,port)) - if err != nil { - return - } - err = l_nouv.Bind(bindusername, bindpassword) - return -} - - -func main() { - var ok bool - bindpassword, ok = os.LookupEnv("BOTTIN_DEFAULT_ADMIN_PW") - if !ok { - if len(os.Args) == 2 { - bindpassword = os.Args[1] - } else { - bindpassword = "" - } - } - - log.Info(fmt.Sprintf("Password selected: %s",bindpassword)) - //log.SetLevel(log.TraceLevel) - - //Create a connection with Bottin server - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", adresse, port)) - //l.Debug = true - printError(err) - - //Bind with the admin account generated - err = l.Bind(bindusername, bindpassword) - printError(err) - - //Create our object Rand, it's important to always have the same values - source := rand.NewSource(666475745) - r := rand.New(source) - log.Info(fmt.Sprintf("The seed of the rand object is %d.\n",r.Seed)) - - //Create user and groups OrgaUnit - err = createOU(l) - if ldap.IsErrorWithCode(err, uint16(68)) { - log.Warn("Les OrganizationalUnit users et groups sont déjà présents.") - }else { - printError(err) - log.Info("Création des OU de groups et users") - } - - //Create random groups - tab_AddRequest_groups, err := createGroup(r, l) - printError(err) - log.Info(fmt.Sprintf("Création des groupes aléatoirement réussi: %d\n", len(tab_AddRequest_groups))) - - //Create random users - tab_AddRequest_users, err := createUser(r, l) - printError(err) - log.Info(fmt.Sprintf("Création des users aléatoirement réussi: %d\n", len(tab_AddRequest_users))) - - //Search and compare attribute Users. (We keep Attribute object from 'Create random users' and compare with the result of our search) - err = test_attributes(l,tab_AddRequest_users, "inetOrgPerson","users") - printError(err) - log.Info("Tous les attributs users insérés dans Consul ont été vérifiés..\n") - - //Search and compare attributes Groups - err = test_attributes(l,tab_AddRequest_groups, "groupOfNames","groups") - printError(err) - log.Info("Tous les attributs groups insérés dans Consul ont été vérifiés.\n") - - - //Close the connection and open an other. If we don't do this, bottin server send a wrong answer. Comment this part if you want to try this - l,err = reconnect(l) - printError(err) - //Modify attributes users and groups. - - //Modify users' attributes and check them - - log.Debug(fmt.Sprintf("Les valeurs sont:\n %s", tab_AddRequest_users)) - err = test_modify_attributes(l, r, tab_AddRequest_users, []string{"displayname"}) - printError(err) - log.Debug("Modifications users faites") - - //Check if the attributes are correct: - err = test_attributes(l,tab_AddRequest_users, "inetOrgPerson", "users") - printError(err) - log.Info("Les modifications ont bien été prises en compte") - log.Debug(fmt.Sprintf("Les nouvelles valeurs sont:\n %s", tab_AddRequest_users)) - - - - - //Modify users' attributes and check them - err = test_modify_attributes(l, r, tab_AddRequest_groups, []string{"description"}) - printError(err) - log.Info("Modifications groups faites") - - //Check if the attributes are correct: - err = test_attributes(l,tab_AddRequest_groups, "groupOfNames", "groups") - printError(err) - log.Info("Les modifications ont bien été prises en compte") - - //Close the connection - l, err = reconnect(l) - printError(err) - - //Add users in group, search them, delete several samples and search again to be sur it's good - err = add_user_in_groups(l, r, tab_AddRequest_users, tab_AddRequest_groups) - printError(err) - log.Info("Ajout d'users dans les groupes fait") - - //Close the connection - l, err = reconnect(l) - printError(err) - - list, err := delete_groups(l, tab_AddRequest_groups) - printError(err) - log.Info("groupe supprimé") - - - l,err = reconnect(l) - printError(err) - - err = check_memberOf(l, list) - printError(err) - log.Info("Le memberOf a été correctement vidé") - - //Clean: Delete all users and groups (not OU users and groups) - err = clean(l, tab_AddRequest_users, tab_AddRequest_groups, true, false) - printError(err) - log.Info("Clean succes") - - defer os.Exit(0) - return - -} diff --git a/test_automatic/rapport_beug_bottin.txt b/test_automatic/rapport_beug_bottin.txt deleted file mode 100644 index 1669e14..0000000 --- a/test_automatic/rapport_beug_bottin.txt +++ /dev/null @@ -1,40 +0,0 @@ -Introduction et Observation premières: - - Lors de la réalisation de mon code Go, j'ai trouvé un beug qui provoquait l'arrêt de mon programme car Bottin envoyé une réponse erronée à mon programme. - Dans logs de Bottin je ne voyais aucune erreur, Bottin n'avait pas cessé de fonctionner. Il s'arrêtait à chaque fois sur mes requêtes Del (mes dernières). - - -Reproduction du beug: - - Pour reproduire le beug, il suffit de lancer le programme interrogation.go et de commenter les lignes suivantes : - -260 //Close the connection and open an other. If we don't do this, bottin server send a wrong answer. Comment this part if you want to try this -261 l.Close() -262 l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d",adresse, port)) -263 printError(err) -264 err = l.Bind(bindusername, bindpassword) -265 printError(err) - - Ainsi on obtient l'erreur suivante: - -2021/07/07 01:25:51 Received unexpected message -128, false - - -Test réalisé pour comprendre la source du problème: - - Ma première hypothèses fut que j'envoyais trop de requêtes dans un court laps de temps et ainsi Bottin ou Consul ne pouvait pas suivre. -J'ai placé un sleep de 50 puis de 100 Millisecondes entre chaque requête, j'obtenais toujours la même erreur. -J'ai essayé de mettre un sleep de 10 secondes avant mes requêtes de suppression mais j'obtenais toujours la même chose. - -Hack pour résoudre: - - La première solution qui a fonctionné était de réduire le nombre de requêtes en n'exécutant pas certains tests random. - La dernière solutions qui est utilisée: - Fermée la connexion puis la réouvrir permet de palier à ce problème - -Hypothèses du problème ?: - - Existerait-il un Buffer par Bind qui se remplirait ? Et lorsque celui-ci est plein, ne renvoie pas d'erreur juste n'arrive plus à répondre. - -Erwan DUFOUR -Deuxfleurs diff --git a/test_automatic/start_test.sh b/test_automatic/start_test.sh deleted file mode 100755 index e7a1712..0000000 --- a/test_automatic/start_test.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -#export BOTTIN_DEFAULT_ADMIN_PW=$(openssl rand -base64 24) -echo $BOTTIN_DEFAULT_ADMIN_PW -consul agent -dev > /dev/null 2>&1 & -sleep 2 -cp test_automatic/config.json.test config.json -./bottin > /dev/null 2>&1 & -sleep 1 -./test_automatic/integration -rm config.json -exit 0 |