github.com/mailru/activerecord@v1.12.2/internal/app/argen_b_test.go (about) 1 package app_test 2 3 import ( 4 "context" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strconv" 12 "testing" 13 14 "github.com/mailru/activerecord/internal/app" 15 "github.com/mailru/activerecord/internal/pkg/ds" 16 "github.com/mailru/activerecord/internal/pkg/testutil" 17 "github.com/mailru/activerecord/pkg/octopus" 18 ) 19 20 func TestInit(t *testing.T) { 21 tempDirs := testutil.InitTmps() 22 defer tempDirs.Defer() 23 24 type args struct { 25 ctx context.Context 26 appInfo ds.AppInfo 27 dirFlag uint32 28 modName string 29 } 30 tests := []struct { 31 name string 32 args args 33 wantNil bool 34 wantErr bool 35 }{ 36 { 37 name: "Non existing src and dst dirs", 38 args: args{ 39 ctx: context.Background(), 40 appInfo: testutil.TestAppInfo, 41 dirFlag: testutil.NonExistsSrcDir | testutil.NonExistsDstDir, 42 modName: "github.com/mailru/activerecord", 43 }, 44 wantNil: true, 45 wantErr: true, 46 }, 47 { 48 name: "non existing dst dir", 49 args: args{ 50 ctx: context.Background(), 51 appInfo: testutil.TestAppInfo, 52 dirFlag: testutil.NonExistsDstDir, 53 }, 54 wantNil: false, 55 wantErr: false, 56 }, 57 { 58 name: "non existing src dir", 59 args: args{ 60 ctx: context.Background(), 61 appInfo: testutil.TestAppInfo, 62 dirFlag: testutil.NonExistsSrcDir, 63 }, 64 wantNil: true, 65 wantErr: true, 66 }, 67 { 68 name: "empty src dir", 69 args: args{ 70 ctx: context.Background(), 71 appInfo: testutil.TestAppInfo, 72 dirFlag: testutil.EmptyDstDir, 73 }, 74 wantNil: false, 75 wantErr: false, 76 }, 77 } 78 for _, tt := range tests { 79 t.Run(tt.name, func(t *testing.T) { 80 srcDir, dstDir, err := tempDirs.CreateDirs(tt.args.dirFlag) 81 if err != nil { 82 t.Errorf("can't prepare temp dirs: %s", err) 83 return 84 } 85 86 got, err := app.Init(tt.args.ctx, &tt.args.appInfo, srcDir, dstDir, "", tt.args.modName) 87 if (err != nil) != tt.wantErr { 88 t.Errorf("Init() error = %v, res = %+v, wantErr %v", err, got, tt.wantErr) 89 return 90 } 91 if (got == nil) != tt.wantNil { 92 t.Errorf("Init() = %+v, wantNil %v", got, tt.wantNil) 93 return 94 } 95 }) 96 } 97 } 98 99 func TestArGen_Run(t *testing.T) { 100 tempDirs := testutil.InitTmps() 101 defer tempDirs.Defer() 102 103 srcRoot, errTmpDir := tempDirs.AddTempDir() 104 if errTmpDir != nil { 105 t.Errorf("can't prepare root tmp dir: %s", errTmpDir) 106 return 107 } 108 109 src := filepath.Join(srcRoot, "model/repository/decl") 110 dst := filepath.Join(srcRoot, "model/repository/argen") 111 112 if err := os.MkdirAll(src, 0700); err != nil { 113 t.Errorf("can't prepare test tmp dir: %s", err) 114 return 115 } 116 117 textTestPkg := `package repository 118 119 //ar:serverHost:127.0.0.1;serverPort:11111;serverTimeout:500 120 //ar:namespace:2 121 //ar:backend:octopus 122 type FieldsFoo struct { 123 Field1 int ` + "`" + `ar:"size:5"` + "`" + ` 124 Field2 string ` + "`" + `ar:"size:5"` + "`" + ` 125 } 126 127 type ( 128 IndexesFoo struct { 129 Field1Field2 bool ` + "`" + `ar:"fields:Field1,Field2;primary_key"` + "`" + ` 130 } 131 IndexPartsFoo struct { 132 Field1Part bool ` + "`" + `ar:"index:Field1Field2;fieldnum:1;selector:SelectByField1"` + "`" + ` 133 } 134 ) 135 136 ` 137 fieldValue := []byte{0x0A, 0x00, 0x00, 0x00} 138 fieldValueStr := strconv.FormatUint(uint64(binary.LittleEndian.Uint32(fieldValue)), 10) 139 namespace := []byte{0x02, 0x00, 0x00, 0x00} 140 insertFlags := []byte{0x03, 0x00, 0x00, 0x00} 141 replaceFlags := []byte{0x05, 0x00, 0x00, 0x00} 142 insertTupleCardinality := []byte{0x02, 0x00, 0x00, 0x00} 143 insertTupleFields := append([]byte{0x04}, fieldValue...) //len + Field1 144 insertTupleFields = append(insertTupleFields, []byte{0x00}...) 145 146 insertReq := append(namespace, insertFlags...) 147 insertReq = append(insertReq, insertTupleCardinality...) 148 insertReq = append(insertReq, insertTupleFields...) 149 150 replaceReq := append(namespace, replaceFlags...) 151 replaceReq = append(replaceReq, insertTupleCardinality...) 152 replaceReq = append(replaceReq, insertTupleFields...) 153 154 insertMsg := octopus.RequestTypeInsert // Insert or Replace 155 156 responseSuccess := []byte{0x00, 0x00, 0x00, 0x00} 157 responseErrorDuplicate := []byte{0x02, 0x20, 0x00, 0x00} 158 insertRespCount := []byte{0x01, 0x00, 0x00, 0x00} 159 insertFqTupleSize := []byte{0x09, 0x00, 0x00, 0x00} //sizeof byte 160 161 successInsertResponse := append(responseSuccess, insertRespCount...) 162 successInsertResponse = append(successInsertResponse, insertFqTupleSize...) 163 successInsertResponse = append(successInsertResponse, insertTupleCardinality...) 164 successInsertResponse = append(successInsertResponse, insertTupleFields...) 165 166 duplicateInsertResponse := append(responseErrorDuplicate, []byte("Duplicate key")...) 167 168 repositoryName := "foo" 169 170 if err := os.WriteFile(filepath.Join(src, repositoryName+".go"), []byte(textTestPkg), 0600); err != nil { 171 t.Errorf("can't write test file: %s", err) 172 return 173 } 174 175 emptySrc, emptyDst, err := tempDirs.CreateDirs(testutil.NonExistsDstDir) 176 if err != nil { 177 t.Errorf("can't initialize dirs: %s", err) 178 return 179 } 180 181 type argsRun struct { 182 testGoMain string 183 fixtures []octopus.FixtureType 184 } 185 186 type initArgs struct { 187 ctx context.Context 188 appInfo ds.AppInfo 189 srcDir string 190 dstDir string 191 dstFixture string 192 root string 193 modName string 194 } 195 196 tests := []struct { 197 name string 198 initArgs initArgs 199 runArgs []argsRun 200 wantErr bool 201 }{ 202 { 203 name: "run on empty src dir", 204 initArgs: initArgs{ 205 ctx: context.Background(), 206 appInfo: testutil.TestAppInfo, 207 srcDir: emptySrc, 208 dstDir: emptyDst, 209 modName: "github.com/mailru/activerecord", 210 }, 211 wantErr: false, 212 }, 213 { 214 name: "simplePkg full cycle", 215 initArgs: initArgs{ 216 ctx: context.Background(), 217 appInfo: testutil.TestAppInfo, 218 srcDir: src, 219 dstDir: dst, 220 root: srcRoot, 221 }, 222 wantErr: false, 223 runArgs: []argsRun{ 224 { 225 testGoMain: `fooRepo := ` + repositoryName + `.New(ctx) 226 fooRepo.SetField1(` + fieldValueStr + `) 227 err := fooRepo.Insert(ctx) 228 if err != nil { 229 log.Fatal(err) 230 } 231 err = fooRepo.Replace(ctx) 232 if err != nil { 233 log.Fatal(err) 234 }`, 235 fixtures: []octopus.FixtureType{ 236 octopus.CreateFixture(1, uint8(insertMsg), insertReq, successInsertResponse, nil), 237 octopus.CreateFixture(2, uint8(insertMsg), replaceReq, successInsertResponse, nil), 238 }, 239 }, 240 { 241 testGoMain: `fooRepo := ` + repositoryName + `.New(ctx) 242 fooRepo.SetField1(` + fieldValueStr + `) 243 err := fooRepo.Insert(ctx) 244 if err == nil { 245 log.Fatal("Error test duplicate") 246 }`, 247 fixtures: []octopus.FixtureType{ 248 octopus.CreateFixture(1, uint8(insertMsg), insertReq, duplicateInsertResponse, nil), 249 }, 250 }, 251 }, 252 }, 253 } 254 255 testModuleName := "github.com/foo/bar/baz/test.git" 256 srcPath := testutil.GetPathToSrc() 257 258 for _, tt := range tests { 259 t.Run(tt.name, func(t *testing.T) { 260 got, err := app.Init(tt.initArgs.ctx, &tt.initArgs.appInfo, tt.initArgs.srcDir, tt.initArgs.dstDir, tt.initArgs.dstFixture, tt.initArgs.modName) 261 if (err != nil) != tt.wantErr { 262 t.Errorf("ArGen.Init() error = %v, wantErr %v", err, tt.wantErr) 263 return 264 } 265 266 if err := got.Run(); (err != nil) != tt.wantErr { 267 t.Errorf("ArGen.Run() error = %v, wantErr %v", err, tt.wantErr) 268 return 269 } 270 271 if tt.runArgs != nil && len(tt.runArgs) > 0 { 272 gomod := `module ` + testModuleName + ` 273 274 go 1.19 275 276 require ( 277 github.com/mailru/activerecord v1.5.4 278 ) 279 280 replace github.com/mailru/activerecord => ` + srcPath 281 282 modFile := filepath.Join(tt.initArgs.root, "/go.mod") 283 if err := os.WriteFile(modFile, []byte(gomod), 0600); err != nil { 284 t.Fatalf(fmt.Sprintf("can't write test script: %s", err)) 285 return 286 } 287 288 oms, err := octopus.InitMockServer(octopus.WithHost("127.0.0.1", "11111")) 289 if err != nil { 290 t.Fatalf(fmt.Sprintf("can't init octopus server: %s", err)) 291 return 292 } 293 294 err = oms.Start() 295 if err != nil { 296 t.Fatalf("Error start octopusMock %s", err) 297 return 298 } 299 300 defer func() { 301 errStop := oms.Stop() 302 if errStop != nil { 303 t.Fatalf("Error stop octopusMock %s", errStop) 304 } 305 }() 306 307 for _, gr := range tt.runArgs { 308 main := `package main 309 310 import ( 311 "context" 312 "fmt" 313 "log" 314 315 "github.com/mailru/activerecord/pkg/activerecord" 316 "` + testModuleName + `/model/repository/argen/` + repositoryName + `" 317 ) 318 319 func main() { 320 ctx := context.Background() 321 log.Printf("Start") 322 activerecord.InitActiveRecord( 323 activerecord.WithConfig(activerecord.NewDefaultConfigFromMap(map[string]interface{}{ 324 "arcfg/master": "127.0.0.1:11111", 325 "arcfg/replica": "127.0.0.1:11111", 326 })), 327 ) 328 ` + gr.testGoMain + ` 329 //activerecord.ConnectionCacher().CloseConnection(ctx) 330 fmt.Print("OK") 331 } 332 ` 333 runFile := filepath.Join(tt.initArgs.root, "/main.go") 334 if err = os.WriteFile(runFile, []byte(main), 0600); err != nil { 335 t.Fatalf(fmt.Sprintf("can't write test script: %s", err)) 336 return 337 } 338 339 oms.SetFixtures(gr.fixtures) 340 341 if _, err = os.Stat(filepath.Join(tt.initArgs.root, "model/repository/argen/foo")); errors.Is(err, os.ErrNotExist) { 342 t.Error("repository file not generated or has invalid name") 343 return 344 } 345 346 cmd := exec.Command("go", "mod", "tidy") 347 cmd.Dir = tt.initArgs.root 348 out, err := cmd.CombinedOutput() 349 if err != nil { 350 t.Fatalf("error run tidy:\n - out: %s\n - err: %s", out, err) 351 } 352 353 cmd = exec.Command("go", "run", runFile) 354 cmd.Dir = tt.initArgs.root 355 out, err = cmd.Output() 356 357 if err != nil { 358 t.Fatalf("Error exec generated model: %s", err.(*exec.ExitError).Stderr) 359 } 360 361 if string(out) != "OK" { 362 t.Fatalf("Exec generated model has bad stdout: %s", out) 363 } 364 } 365 } 366 }) 367 } 368 }