get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/test/ports_test.go (about) 1 // Copyright 2018-2019 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package test 15 16 import ( 17 "encoding/json" 18 "errors" 19 "fmt" 20 "os" 21 "path/filepath" 22 "strings" 23 "testing" 24 "time" 25 26 "get.pme.sh/pnats/server" 27 ) 28 29 // waits until a calculated list of listeners is resolved or a timeout 30 func waitForFile(path string, dur time.Duration) ([]byte, error) { 31 end := time.Now().Add(dur) 32 for time.Now().Before(end) { 33 if _, err := os.Stat(path); os.IsNotExist(err) { 34 time.Sleep(25 * time.Millisecond) 35 continue 36 } else { 37 return os.ReadFile(path) 38 } 39 } 40 return nil, errors.New("Timeout") 41 } 42 43 func portFile(dirname string) string { 44 return filepath.Join(dirname, fmt.Sprintf("%s_%d.ports", filepath.Base(os.Args[0]), os.Getpid())) 45 } 46 47 func TestPortsFile(t *testing.T) { 48 portFileDir := t.TempDir() 49 50 opts := DefaultTestOptions 51 opts.PortsFileDir = portFileDir 52 opts.Port = -1 53 opts.HTTPPort = -1 54 opts.ProfPort = -1 55 opts.Cluster.Port = -1 56 opts.Websocket.Port = -1 57 tc := &server.TLSConfigOpts{ 58 CertFile: "./configs/certs/server-cert.pem", 59 KeyFile: "./configs/certs/server-key.pem", 60 } 61 opts.Websocket.TLSConfig, _ = server.GenTLSConfig(tc) 62 63 s := RunServer(&opts) 64 // this for test cleanup in case we fail - will be ignored if server already shutdown 65 defer s.Shutdown() 66 67 ports := s.PortsInfo(5 * time.Second) 68 69 if ports == nil { 70 t.Fatal("services failed to start in 5 seconds") 71 } 72 73 // the pid file should be 74 portsFile := portFile(portFileDir) 75 76 if portsFile == "" { 77 t.Fatal("Expected a ports file") 78 } 79 80 // try to read a file here - the file should be a json 81 buf, err := waitForFile(portsFile, 5*time.Second) 82 if err != nil { 83 t.Fatalf("Could not read ports file: %v", err) 84 } 85 if len(buf) <= 0 { 86 t.Fatal("Expected a non-zero length ports file") 87 } 88 89 readPorts := server.Ports{} 90 json.Unmarshal(buf, &readPorts) 91 92 if len(readPorts.Nats) == 0 || !strings.HasPrefix(readPorts.Nats[0], "nats://") { 93 t.Fatal("Expected at least one nats url") 94 } 95 96 if len(readPorts.Monitoring) == 0 || !strings.HasPrefix(readPorts.Monitoring[0], "http://") { 97 t.Fatal("Expected at least one monitoring url") 98 } 99 100 if len(readPorts.Cluster) == 0 || !strings.HasPrefix(readPorts.Cluster[0], "nats://") { 101 t.Fatal("Expected at least one cluster listen url") 102 } 103 104 if len(readPorts.Profile) == 0 || !strings.HasPrefix(readPorts.Profile[0], "http://") { 105 t.Fatal("Expected at least one profile listen url") 106 } 107 108 if len(readPorts.WebSocket) == 0 || !strings.HasPrefix(readPorts.WebSocket[0], "wss://") { 109 t.Fatal("Expected at least one ws listen url") 110 } 111 112 // testing cleanup 113 s.Shutdown() 114 // if we called shutdown, the cleanup code should have kicked 115 if _, err := os.Stat(portsFile); os.IsNotExist(err) { 116 // good 117 } else { 118 t.Fatalf("the port file %s was not deleted", portsFile) 119 } 120 } 121 122 // makes a temp directory with two directories 'A' and 'B' 123 // the location of the ports file is changed from dir A to dir B. 124 func TestPortsFileReload(t *testing.T) { 125 tempDir := t.TempDir() 126 127 // make child temp dir A 128 dirA := filepath.Join(tempDir, "A") 129 os.MkdirAll(dirA, 0777) 130 131 // write the config file with a reference to A 132 config := fmt.Sprintf(` 133 ports_file_dir: "%s" 134 port: -1 135 `, dirA) 136 config = strings.Replace(config, "\\", "/", -1) 137 confPath := filepath.Join(tempDir, fmt.Sprintf("%d.conf", os.Getpid())) 138 if err := os.WriteFile(confPath, []byte(config), 0666); err != nil { 139 t.Fatalf("Error writing ports file (%s): %v", confPath, err) 140 } 141 142 opts, err := server.ProcessConfigFile(confPath) 143 if err != nil { 144 t.Fatalf("Error processing the configuration: %v", err) 145 } 146 147 s := RunServer(opts) 148 defer s.Shutdown() 149 150 ports := s.PortsInfo(5 * time.Second) 151 if ports == nil { 152 t.Fatal("services failed to start in 5 seconds") 153 } 154 155 // get the ports file path name 156 portsFileInA := portFile(dirA) 157 // the file should be in dirA 158 if !strings.HasPrefix(portsFileInA, dirA) { 159 t.Fatalf("expected ports file to be in [%s] but was in [%s]", dirA, portsFileInA) 160 } 161 // wait for it 162 buf, err := waitForFile(portsFileInA, 5*time.Second) 163 if err != nil { 164 t.Fatalf("Could not read ports file: %v", err) 165 } 166 if len(buf) <= 0 { 167 t.Fatal("Expected a non-zero length ports file") 168 } 169 170 // change the configuration for the ports file to dirB 171 dirB := filepath.Join(tempDir, "B") 172 os.MkdirAll(dirB, 0777) 173 174 config = fmt.Sprintf(` 175 ports_file_dir: "%s" 176 port: -1 177 `, dirB) 178 config = strings.Replace(config, "\\", "/", -1) 179 if err := os.WriteFile(confPath, []byte(config), 0666); err != nil { 180 t.Fatalf("Error writing ports file (%s): %v", confPath, err) 181 } 182 183 // reload the server 184 if err := s.Reload(); err != nil { 185 t.Fatalf("error reloading server: %v", err) 186 } 187 188 // wait for the new file to show up 189 portsFileInB := portFile(dirB) 190 buf, err = waitForFile(portsFileInB, 5*time.Second) 191 if !strings.HasPrefix(portsFileInB, dirB) { 192 t.Fatalf("expected ports file to be in [%s] but was in [%s]", dirB, portsFileInB) 193 } 194 if err != nil { 195 t.Fatalf("Could not read ports file: %v", err) 196 } 197 if len(buf) <= 0 { 198 t.Fatal("Expected a non-zero length ports file") 199 } 200 201 // the file in dirA should have deleted 202 if _, err := os.Stat(portsFileInA); os.IsNotExist(err) { 203 // good 204 } else { 205 t.Fatalf("the port file %s was not deleted", portsFileInA) 206 } 207 }